aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/filesystems/Locking2
-rw-r--r--Documentation/filesystems/vfs.txt4
-rw-r--r--Documentation/s390/CommonIO11
-rw-r--r--MAINTAINERS6
-rw-r--r--arch/cris/kernel/sys_cris.c5
-rw-r--r--arch/m32r/kernel/sys_m32r.c5
-rw-r--r--arch/s390/Kconfig7
-rw-r--r--arch/s390/kernel/compat_wrapper.S2
-rw-r--r--arch/s390/kernel/entry.S29
-rw-r--r--arch/s390/kernel/entry64.S57
-rw-r--r--arch/s390/kernel/ptrace.c100
-rw-r--r--arch/s390/kvm/Kconfig1
-rw-r--r--arch/s390/kvm/intercept.c3
-rw-r--r--arch/s390/kvm/kvm-s390.c5
-rw-r--r--arch/s390/mm/Makefile1
-rw-r--r--arch/s390/mm/init.c3
-rw-r--r--arch/s390/mm/page-states.c79
-rw-r--r--arch/sparc/kernel/process.c20
-rw-r--r--arch/sparc/kernel/sys_sparc.c3
-rw-r--r--arch/sparc64/kernel/process.c18
-rw-r--r--arch/sparc64/kernel/smp.c27
-rw-r--r--arch/sparc64/kernel/sys_sparc.c4
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c31
-rw-r--r--arch/sparc64/kernel/systbls.S2
-rw-r--r--arch/sparc64/mm/init.c16
-rw-r--r--arch/um/Makefile5
-rw-r--r--arch/um/drivers/line.c4
-rw-r--r--arch/um/include/line.h2
-rw-r--r--arch/x86/mm/pgtable_32.c7
-rw-r--r--block/blk-core.c26
-rw-r--r--block/blk-ioc.c2
-rw-r--r--block/blk-merge.c12
-rw-r--r--block/blk-sysfs.c6
-rw-r--r--block/blk-tag.c9
-rw-r--r--block/cfq-iosched.c23
-rw-r--r--drivers/accessibility/Kconfig12
-rw-r--r--drivers/ata/Kconfig13
-rw-r--r--drivers/ata/Makefile1
-rw-r--r--drivers/ata/ahci.c4
-rw-r--r--drivers/ata/ata_generic.c6
-rw-r--r--drivers/ata/ata_piix.c25
-rw-r--r--drivers/ata/libata-core.c1
-rw-r--r--drivers/ata/libata-eh.c2
-rw-r--r--drivers/ata/libata-sff.c6
-rw-r--r--drivers/ata/pata_acpi.c6
-rw-r--r--drivers/ata/pata_sch.c206
-rw-r--r--drivers/ata/sata_inic162x.c646
-rw-r--r--drivers/ata/sata_mv.c690
-rw-r--r--drivers/base/sys.c3
-rw-r--r--drivers/block/aoe/aoecmd.c10
-rw-r--r--drivers/char/sx.c9
-rw-r--r--drivers/char/vt.c6
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_hal.c90
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_hal.h8
-rw-r--r--drivers/infiniband/hw/cxgb3/cxio_resource.c36
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_mem.c75
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.c68
-rw-r--r--drivers/infiniband/hw/cxgb3/iwch_provider.h8
-rw-r--r--drivers/infiniband/hw/ehca/ehca_classes.h2
-rw-r--r--drivers/infiniband/hw/ehca/ehca_irq.c4
-rw-r--r--drivers/infiniband/hw/ehca/ehca_qp.c5
-rw-r--r--drivers/infiniband/hw/ipath/ipath_driver.c138
-rw-r--r--drivers/infiniband/hw/ipath/ipath_file_ops.c72
-rw-r--r--drivers/infiniband/hw/ipath/ipath_iba7220.c26
-rw-r--r--drivers/infiniband/hw/ipath/ipath_init_chip.c95
-rw-r--r--drivers/infiniband/hw/ipath/ipath_intr.c80
-rw-r--r--drivers/infiniband/hw/ipath/ipath_kernel.h8
-rw-r--r--drivers/infiniband/hw/ipath/ipath_rc.c6
-rw-r--r--drivers/infiniband/hw/ipath/ipath_ruc.c7
-rw-r--r--drivers/infiniband/hw/ipath/ipath_sdma.c44
-rw-r--r--drivers/infiniband/hw/ipath/ipath_verbs.c2
-rw-r--r--drivers/md/raid10.c2
-rw-r--r--drivers/media/Makefile2
-rw-r--r--drivers/media/video/cx18/cx18-driver.c2
-rw-r--r--drivers/media/video/saa7134/saa7134-video.c2
-rw-r--r--drivers/net/irda/nsc-ircc.c6
-rw-r--r--drivers/net/irda/smsc-ircc2.c5
-rw-r--r--drivers/net/niu.c11
-rw-r--r--drivers/net/usb/asix.c4
-rw-r--r--drivers/net/wan/lapbether.c1
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig3
-rw-r--r--drivers/rtc/rtc-ds1511.c4
-rw-r--r--drivers/s390/char/tty3270.c15
-rw-r--r--drivers/s390/cio/blacklist.c323
-rw-r--r--drivers/s390/cio/cio.c39
-rw-r--r--drivers/s390/cio/cio.h2
-rw-r--r--drivers/s390/cio/cio_debug.h6
-rw-r--r--drivers/s390/cio/css.c4
-rw-r--r--drivers/s390/cio/device.c25
-rw-r--r--drivers/s390/cio/device_fsm.c44
-rw-r--r--drivers/s390/cio/device_id.c4
-rw-r--r--drivers/s390/cio/device_pgid.c12
-rw-r--r--drivers/s390/s390mach.c3
-rw-r--r--drivers/sbus/char/bpp.c2
-rw-r--r--drivers/scsi/dpt_i2o.c78
-rw-r--r--drivers/scsi/dpti.h13
-rw-r--r--drivers/serial/serial_core.c3
-rw-r--r--drivers/usb/host/Kconfig2
-rw-r--r--drivers/usb/serial/iuu_phoenix.c6
-rw-r--r--drivers/video/bw2.c2
-rw-r--r--drivers/video/cg3.c2
-rw-r--r--drivers/video/cg6.c2
-rw-r--r--drivers/video/ffb.c2
-rw-r--r--drivers/video/leo.c2
-rw-r--r--drivers/video/p9100.c2
-rw-r--r--drivers/video/tcx.c20
-rw-r--r--fs/affs/affs.h4
-rw-r--r--fs/affs/file.c25
-rw-r--r--fs/affs/inode.c34
-rw-r--r--fs/affs/namei.c6
-rw-r--r--fs/affs/super.c18
-rw-r--r--fs/bio.c3
-rw-r--r--fs/inode.c5
-rw-r--r--fs/locks.c17
-rw-r--r--fs/pipe.c6
-rw-r--r--fs/proc/task_mmu.c2
-rw-r--r--fs/splice.c31
-rw-r--r--fs/udf/namei.c145
-rw-r--r--fs/udf/partition.c4
-rw-r--r--fs/udf/super.c1
-rw-r--r--fs/udf/udfdecl.h1
-rw-r--r--include/asm-mn10300/processor.h2
-rw-r--r--include/asm-s390/kvm_host.h1
-rw-r--r--include/asm-s390/page.h11
-rw-r--r--include/asm-s390/ptrace.h2
-rw-r--r--include/asm-s390/system.h6
-rw-r--r--include/asm-x86/pgtable_32.h9
-rw-r--r--include/asm-x86/pgtable_64.h6
-rw-r--r--include/linux/exportfs.h21
-rw-r--r--include/linux/fs.h6
-rw-r--r--include/linux/genhd.h35
-rw-r--r--include/linux/ioprio.h14
-rw-r--r--include/linux/libata.h16
-rw-r--r--include/net/ip.h2
-rw-r--r--include/net/xfrm.h48
-rw-r--r--kernel/cpuset.c52
-rw-r--r--kernel/relay.c2
-rw-r--r--mm/filemap.c2
-rw-r--r--mm/memory.c5
-rw-r--r--mm/slub.c2
-rw-r--r--net/atm/br2684.c4
-rw-r--r--net/bridge/br_if.c12
-rw-r--r--net/core/skbuff.c4
-rw-r--r--net/dccp/feat.c2
-rw-r--r--net/decnet/dn_route.c12
-rw-r--r--net/ipv4/route.c18
-rw-r--r--net/ipv4/tcp_input.c15
-rw-r--r--net/ipv6/route.c6
-rw-r--r--net/mac80211/main.c7
-rw-r--r--net/mac80211/rc80211_pid_debugfs.c4
-rw-r--r--net/sched/act_simple.c45
-rw-r--r--net/sched/sch_htb.c8
-rw-r--r--net/sunrpc/svc.c1
-rw-r--r--sound/oss/kahlua.c2
154 files changed, 2751 insertions, 1545 deletions
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index c2992bc54f2..8b22d7d8b99 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -92,7 +92,6 @@ prototypes:
void (*destroy_inode)(struct inode *);
void (*dirty_inode) (struct inode *);
int (*write_inode) (struct inode *, int);
- void (*put_inode) (struct inode *);
void (*drop_inode) (struct inode *);
void (*delete_inode) (struct inode *);
void (*put_super) (struct super_block *);
@@ -115,7 +114,6 @@ alloc_inode: no no no
destroy_inode: no
dirty_inode: no (must not sleep)
write_inode: no
-put_inode: no
drop_inode: no !!!inode_lock!!!
delete_inode: no
put_super: yes yes no
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index 81e5be6e6e3..b7522c6cbae 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -205,7 +205,6 @@ struct super_operations {
void (*dirty_inode) (struct inode *);
int (*write_inode) (struct inode *, int);
- void (*put_inode) (struct inode *);
void (*drop_inode) (struct inode *);
void (*delete_inode) (struct inode *);
void (*put_super) (struct super_block *);
@@ -246,9 +245,6 @@ or bottom half).
inode to disc. The second parameter indicates whether the write
should be synchronous or not, not all filesystems check this flag.
- put_inode: called when the VFS inode is removed from the inode
- cache.
-
drop_inode: called when the last access to the inode is dropped,
with the inode_lock spinlock held.
diff --git a/Documentation/s390/CommonIO b/Documentation/s390/CommonIO
index 8fbc0a85287..bf0baa19ec2 100644
--- a/Documentation/s390/CommonIO
+++ b/Documentation/s390/CommonIO
@@ -8,17 +8,6 @@ Command line parameters
Enable logging of debug information in case of ccw device timeouts.
-
-* cio_msg = yes | no
-
- Determines whether information on found devices and sensed device
- characteristics should be shown during startup or when new devices are
- found, i. e. messages of the types "Detected device 0.0.4711 on subchannel
- 0.0.0042" and "SenseID: Device 0.0.4711 reports: ...".
-
- Default is off.
-
-
* cio_ignore = {all} |
{<device> | <range of devices>} |
{!<device> | !<range of devices>}
diff --git a/MAINTAINERS b/MAINTAINERS
index abe27871ad6..f5583dc7ea3 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2112,12 +2112,10 @@ L: netdev@vger.kernel.org
S: Maintained
INTEL ETHERNET DRIVERS (e100/e1000/e1000e/igb/ixgb/ixgbe)
-P: Auke Kok
-M: auke-jan.h.kok@intel.com
-P: Jesse Brandeburg
-M: jesse.brandeburg@intel.com
P: Jeff Kirsher
M: jeffrey.t.kirsher@intel.com
+P: Jesse Brandeburg
+M: jesse.brandeburg@intel.com
P: Bruce Allan
M: bruce.w.allan@intel.com
P: John Ronciak
diff --git a/arch/cris/kernel/sys_cris.c b/arch/cris/kernel/sys_cris.c
index 8b9984197ed..d124066e172 100644
--- a/arch/cris/kernel/sys_cris.c
+++ b/arch/cris/kernel/sys_cris.c
@@ -40,8 +40,11 @@ asmlinkage int sys_pipe(unsigned long __user * fildes)
error = do_pipe(fd);
unlock_kernel();
if (!error) {
- if (copy_to_user(fildes, fd, 2*sizeof(int)))
+ if (copy_to_user(fildes, fd, 2*sizeof(int))) {
+ sys_close(fd[0]);
+ sys_close(fd[1]);
error = -EFAULT;
+ }
}
return error;
}
diff --git a/arch/m32r/kernel/sys_m32r.c b/arch/m32r/kernel/sys_m32r.c
index 6d7a80fdad4..319c79720b8 100644
--- a/arch/m32r/kernel/sys_m32r.c
+++ b/arch/m32r/kernel/sys_m32r.c
@@ -90,8 +90,11 @@ sys_pipe(unsigned long r0, unsigned long r1, unsigned long r2,
error = do_pipe(fd);
if (!error) {
- if (copy_to_user((void __user *)r0, fd, 2*sizeof(int)))
+ if (copy_to_user((void __user *)r0, fd, 2*sizeof(int))) {
+ sys_close(fd[0]);
+ sys_close(fd[1]);
error = -EFAULT;
+ }
}
return error;
}
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 29a7940f284..1d035082e78 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -430,6 +430,13 @@ config CMM_IUCV
Select this option to enable the special message interface to
the cooperative memory management.
+config PAGE_STATES
+ bool "Unused page notification"
+ help
+ This enables the notification of unused pages to the
+ hypervisor. The ESSA instruction is used to do the states
+ changes between a page that has content and the unused state.
+
config VIRT_TIMER
bool "Virtual CPU timer support"
help
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
index 743d54f0b8d..d003a6e16af 100644
--- a/arch/s390/kernel/compat_wrapper.S
+++ b/arch/s390/kernel/compat_wrapper.S
@@ -121,7 +121,7 @@ sys32_ptrace_wrapper:
lgfr %r3,%r3 # long
llgtr %r4,%r4 # long
llgfr %r5,%r5 # long
- jg sys_ptrace # branch to system call
+ jg compat_sys_ptrace # branch to system call
.globl sys32_alarm_wrapper
sys32_alarm_wrapper:
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index bdbb3bcd78a..708cf9cf9a3 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -279,8 +279,6 @@ sysc_do_restart:
st %r2,SP_R2(%r15) # store return value (change R2 on stack)
sysc_return:
- tm SP_PSW+1(%r15),0x01 # returning to user ?
- bno BASED(sysc_restore)
tm __TI_flags+3(%r9),_TIF_WORK_SVC
bnz BASED(sysc_work) # there is work to do (signals etc.)
sysc_restore:
@@ -312,6 +310,8 @@ sysc_work_loop:
# One of the work bits is on. Find out which one.
#
sysc_work:
+ tm SP_PSW+1(%r15),0x01 # returning to user ?
+ bno BASED(sysc_restore)
tm __TI_flags+3(%r9),_TIF_MCCK_PENDING
bo BASED(sysc_mcck_pending)
tm __TI_flags+3(%r9),_TIF_NEED_RESCHED
@@ -602,12 +602,6 @@ io_no_vtime:
la %r2,SP_PTREGS(%r15) # address of register-save area
basr %r14,%r1 # branch to standard irq handler
io_return:
- tm SP_PSW+1(%r15),0x01 # returning to user ?
-#ifdef CONFIG_PREEMPT
- bno BASED(io_preempt) # no -> check for preemptive scheduling
-#else
- bno BASED(io_restore) # no-> skip resched & signal
-#endif
tm __TI_flags+3(%r9),_TIF_WORK_INT
bnz BASED(io_work) # there is work to do (signals etc.)
io_restore:
@@ -629,10 +623,18 @@ io_restore_trace_psw:
.long 0, io_restore_trace + 0x80000000
#endif
-#ifdef CONFIG_PREEMPT
-io_preempt:
+#
+# switch to kernel stack, then check the TIF bits
+#
+io_work:
+ tm SP_PSW+1(%r15),0x01 # returning to user ?
+#ifndef CONFIG_PREEMPT
+ bno BASED(io_restore) # no-> skip resched & signal
+#else
+ bnz BASED(io_work_user) # no -> check for preemptive scheduling
+ # check for preemptive scheduling
icm %r0,15,__TI_precount(%r9)
- bnz BASED(io_restore)
+ bnz BASED(io_restore) # preemption disabled
l %r1,SP_R15(%r15)
s %r1,BASED(.Lc_spsize)
mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
@@ -646,10 +648,7 @@ io_resume_loop:
br %r1 # call schedule
#endif
-#
-# switch to kernel stack, then check the TIF bits
-#
-io_work:
+io_work_user:
l %r1,__LC_KERNEL_STACK
s %r1,BASED(.Lc_spsize)
mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 5a4a7bcd2bb..fee10177dbf 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -271,8 +271,6 @@ sysc_noemu:
stg %r2,SP_R2(%r15) # store return value (change R2 on stack)
sysc_return:
- tm SP_PSW+1(%r15),0x01 # returning to user ?
- jno sysc_restore
tm __TI_flags+7(%r9),_TIF_WORK_SVC
jnz sysc_work # there is work to do (signals etc.)
sysc_restore:
@@ -304,6 +302,8 @@ sysc_work_loop:
# One of the work bits is on. Find out which one.
#
sysc_work:
+ tm SP_PSW+1(%r15),0x01 # returning to user ?
+ jno sysc_restore
tm __TI_flags+7(%r9),_TIF_MCCK_PENDING
jo sysc_mcck_pending
tm __TI_flags+7(%r9),_TIF_NEED_RESCHED
@@ -585,12 +585,6 @@ io_no_vtime:
la %r2,SP_PTREGS(%r15) # address of register-save area
brasl %r14,do_IRQ # call standard irq handler
io_return:
- tm SP_PSW+1(%r15),0x01 # returning to user ?
-#ifdef CONFIG_PREEMPT
- jno io_preempt # no -> check for preemptive scheduling
-#else
- jno io_restore # no-> skip resched & signal
-#endif
tm __TI_flags+7(%r9),_TIF_WORK_INT
jnz io_work # there is work to do (signals etc.)
io_restore:
@@ -612,10 +606,41 @@ io_restore_trace_psw:
.quad 0, io_restore_trace
#endif
-#ifdef CONFIG_PREEMPT
-io_preempt:
+#
+# There is work todo, we need to check if we return to userspace, then
+# check, if we are in SIE, if yes leave it
+#
+io_work:
+ tm SP_PSW+1(%r15),0x01 # returning to user ?
+#ifndef CONFIG_PREEMPT
+#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
+ jnz io_work_user # yes -> no need to check for SIE
+ la %r1, BASED(sie_opcode) # we return to kernel here
+ lg %r2, SP_PSW+8(%r15)
+ clc 0(2,%r1), 0(%r2) # is current instruction = SIE?
+ jne io_restore # no-> return to kernel
+ lg %r1, SP_PSW+8(%r15) # yes-> add 4 bytes to leave SIE
+ aghi %r1, 4
+ stg %r1, SP_PSW+8(%r15)
+ j io_restore # return to kernel
+#else
+ jno io_restore # no-> skip resched & signal
+#endif
+#else
+ jnz io_work_user # yes -> do resched & signal
+#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
+ la %r1, BASED(sie_opcode)
+ lg %r2, SP_PSW+8(%r15)
+ clc 0(2,%r1), 0(%r2) # is current instruction = SIE?
+ jne 0f # no -> leave PSW alone
+ lg %r1, SP_PSW+8(%r15) # yes-> add 4 bytes to leave SIE
+ aghi %r1, 4
+ stg %r1, SP_PSW+8(%r15)
+0:
+#endif
+ # check for preemptive scheduling
icm %r0,15,__TI_precount(%r9)
- jnz io_restore
+ jnz io_restore # preemption is disabled
# switch to kernel stack
lg %r1,SP_R15(%r15)
aghi %r1,-SP_SIZE
@@ -629,10 +654,7 @@ io_resume_loop:
jg preempt_schedule_irq
#endif
-#
-# switch to kernel stack, then check TIF bits
-#
-io_work:
+io_work_user:
lg %r1,__LC_KERNEL_STACK
aghi %r1,-SP_SIZE
mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
@@ -653,6 +675,11 @@ io_work_loop:
j io_restore
io_work_done:
+#if defined(CONFIG_KVM) || defined(CONFIG_KVM_MODULE)
+sie_opcode:
+ .long 0xb2140000
+#endif
+
#
# _TIF_MCCK_PENDING is set, call handler
#
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index 7f427016374..35827b9bd4d 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -292,8 +292,7 @@ poke_user(struct task_struct *child, addr_t addr, addr_t data)
return 0;
}
-static int
-do_ptrace_normal(struct task_struct *child, long request, long addr, long data)
+long arch_ptrace(struct task_struct *child, long request, long addr, long data)
{
ptrace_area parea;
int copied, ret;
@@ -529,35 +528,19 @@ poke_user_emu31(struct task_struct *child, addr_t addr, addr_t data)
return 0;
}
-static int
-do_ptrace_emu31(struct task_struct *child, long request, long addr, long data)
+long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
+ compat_ulong_t caddr, compat_ulong_t cdata)
{
- unsigned int tmp; /* 4 bytes !! */
+ unsigned long addr = caddr;
+ unsigned long data = cdata;
ptrace_area_emu31 parea;
int copied, ret;
switch (request) {
- case PTRACE_PEEKTEXT:
- case PTRACE_PEEKDATA:
- /* read word at location addr. */
- copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
- if (copied != sizeof(tmp))
- return -EIO;
- return put_user(tmp, (unsigned int __force __user *) data);
-
case PTRACE_PEEKUSR:
/* read the word at location addr in the USER area. */
return peek_user_emu31(child, addr, data);
- case PTRACE_POKETEXT:
- case PTRACE_POKEDATA:
- /* write the word at location addr. */
- tmp = data;
- copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 1);
- if (copied != sizeof(tmp))
- return -EIO;
- return 0;
-
case PTRACE_POKEUSR:
/* write the word at location addr in the USER area */
return poke_user_emu31(child, addr, data);
@@ -587,82 +570,11 @@ do_ptrace_emu31(struct task_struct *child, long request, long addr, long data)
copied += sizeof(unsigned int);
}
return 0;
- case PTRACE_GETEVENTMSG:
- return put_user((__u32) child->ptrace_message,
- (unsigned int __force __user *) data);
- case PTRACE_GETSIGINFO:
- if (child->last_siginfo == NULL)
- return -EINVAL;
- return copy_siginfo_to_user32((compat_siginfo_t
- __force __user *) data,
- child->last_siginfo);
- case PTRACE_SETSIGINFO:
- if (child->last_siginfo == NULL)
- return -EINVAL;
- return copy_siginfo_from_user32(child->last_siginfo,
- (compat_siginfo_t
- __force __user *) data);
}
- return ptrace_request(child, request, addr, data);
+ return compat_ptrace_request(child, request, addr, data);
}
#endif
-long arch_ptrace(struct task_struct *child, long request, long addr, long data)
-{
- switch (request) {
- case PTRACE_SYSCALL:
- /* continue and stop at next (return from) syscall */
- case PTRACE_CONT:
- /* restart after signal. */
- if (!valid_signal(data))
- return -EIO;
- if (request == PTRACE_SYSCALL)
- set_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- else
- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- child->exit_code = data;
- /* make sure the single step bit is not set. */
- user_disable_single_step(child);
- wake_up_process(child);
- return 0;
-
- case PTRACE_KILL:
- /*
- * make the child exit. Best I can do is send it a sigkill.
- * perhaps it should be put in the status that it wants to
- * exit.
- */
- if (child->exit_state == EXIT_ZOMBIE) /* already dead */
- return 0;
- child->exit_code = SIGKILL;
- /* make sure the single step bit is not set. */
- user_disable_single_step(child);
- wake_up_process(child);
- return 0;
-
- case PTRACE_SINGLESTEP:
- /* set the trap flag. */
- if (!valid_signal(data))
- return -EIO;
- clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
- child->exit_code = data;
- user_enable_single_step(child);
- /* give it a chance to run. */
- wake_up_process(child);
- return 0;
-
- /* Do requests that differ for 31/64 bit */
- default:
-#ifdef CONFIG_COMPAT
- if (test_thread_flag(TIF_31BIT))
- return do_ptrace_emu31(child, request, addr, data);
-#endif
- return do_ptrace_normal(child, request, addr, data);
- }
- /* Not reached. */
- return -EIO;
-}
-
asmlinkage void
syscall_trace(struct pt_regs *regs, int entryexit)
{
diff --git a/arch/s390/kvm/Kconfig b/arch/s390/kvm/Kconfig
index 1761b74d639..e051cad1f1e 100644
--- a/arch/s390/kvm/Kconfig
+++ b/arch/s390/kvm/Kconfig
@@ -22,7 +22,6 @@ config KVM
select PREEMPT_NOTIFIERS
select ANON_INODES
select S390_SWITCH_AMODE
- select PREEMPT
---help---
Support hosting paravirtualized guest machines using the SIE
virtualization capability on the mainframe. This should work
diff --git a/arch/s390/kvm/intercept.c b/arch/s390/kvm/intercept.c
index 349581a2610..47a0b642174 100644
--- a/arch/s390/kvm/intercept.c
+++ b/arch/s390/kvm/intercept.c
@@ -105,6 +105,9 @@ static intercept_handler_t instruction_handlers[256] = {
static int handle_noop(struct kvm_vcpu *vcpu)
{
switch (vcpu->arch.sie_block->icptcode) {
+ case 0x0:
+ vcpu->stat.exit_null++;
+ break;
case 0x10:
vcpu->stat.exit_external_request++;
break;
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 98d1e73e01f..0ac36a649eb 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -31,6 +31,7 @@
struct kvm_stats_debugfs_item debugfs_entries[] = {
{ "userspace_handled", VCPU_STAT(exit_userspace) },
+ { "exit_null", VCPU_STAT(exit_null) },
{ "exit_validity", VCPU_STAT(exit_validity) },
{ "exit_stop_request", VCPU_STAT(exit_stop_request) },
{ "exit_external_request", VCPU_STAT(exit_external_request) },
@@ -221,10 +222,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
vcpu->arch.guest_fpregs.fpc &= FPC_VALID_MASK;
restore_fp_regs(&vcpu->arch.guest_fpregs);
restore_access_regs(vcpu->arch.guest_acrs);
-
- if (signal_pending(current))
- atomic_set_mask(CPUSTAT_STOP_INT,
- &vcpu->arch.sie_block->cpuflags);
}
void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
diff --git a/arch/s390/mm/Makefile b/arch/s390/mm/Makefile
index fb988a48a75..2a745813454 100644
--- a/arch/s390/mm/Makefile
+++ b/arch/s390/mm/Makefile
@@ -5,3 +5,4 @@
obj-y := init.o fault.o extmem.o mmap.o vmem.o pgtable.o
obj-$(CONFIG_CMM) += cmm.o
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
+obj-$(CONFIG_PAGE_STATES) += page-states.o
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
index fa31de6ae97..29f3a63806b 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -126,6 +126,9 @@ void __init mem_init(void)
/* clear the zero-page */
memset(empty_zero_page, 0, PAGE_SIZE);
+ /* Setup guest page hinting */
+ cmma_init();
+
/* this will put all low memory onto the freelists */
totalram_pages += free_all_bootmem();
diff --git a/arch/s390/mm/page-states.c b/arch/s390/mm/page-states.c
new file mode 100644
index 00000000000..fc0ad73ffd9
--- /dev/null
+++ b/arch/s390/mm/page-states.c
@@ -0,0 +1,79 @@
+/*
+ * arch/s390/mm/page-states.c
+ *
+ * Copyright IBM Corp. 2008
+ *
+ * Guest page hinting for unused pages.
+ *
+ * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+
+#define ESSA_SET_STABLE 1
+#define ESSA_SET_UNUSED 2
+
+static int cmma_flag;
+
+static int __init cmma(char *str)
+{
+ char *parm;
+ parm = strstrip(str);
+ if (strcmp(parm, "yes") == 0 || strcmp(parm, "on") == 0) {
+ cmma_flag = 1;
+ return 1;
+ }
+ cmma_flag = 0;
+ if (strcmp(parm, "no") == 0 || strcmp(parm, "off") == 0)
+ return 1;
+ return 0;
+}
+
+__setup("cmma=", cmma);
+
+void __init cmma_init(void)
+{
+ register unsigned long tmp asm("0") = 0;
+ register int rc asm("1") = -EOPNOTSUPP;
+
+ if (!cmma_flag)
+ return;
+ asm volatile(
+ " .insn rrf,0xb9ab0000,%1,%1,0,0\n"
+ "0: la %0,0\n"
+ "1:\n"
+ EX_TABLE(0b,1b)
+ : "+&d" (rc), "+&d" (tmp));
+ if (rc)
+ cmma_flag = 0;
+}
+
+void arch_free_page(struct page *page, int order)
+{
+ int i, rc;
+
+ if (!cmma_flag)
+ return;
+ for (i = 0; i < (1 << order); i++)
+ asm volatile(".insn rrf,0xb9ab0000,%0,%1,%2,0"
+ : "=&d" (rc)
+ : "a" ((page_to_pfn(page) + i) << PAGE_SHIFT),
+ "i" (ESSA_SET_UNUSED));
+}
+
+void arch_alloc_page(struct page *page, int order)
+{
+ int i, rc;
+
+ if (!cmma_flag)
+ return;
+ for (i = 0; i < (1 << order); i++)
+ asm volatile(".insn rrf,0xb9ab0000,%0,%1,%2,0"
+ : "=&d" (rc)
+ : "a" ((page_to_pfn(page) + i) << PAGE_SHIFT),
+ "i" (ESSA_SET_STABLE));
+}
diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
index e7f35198ae3..36431f377de 100644
--- a/arch/sparc/kernel/process.c
+++ b/arch/sparc/kernel/process.c
@@ -419,14 +419,26 @@ asmlinkage int sparc_do_fork(unsigned long clone_flags,
unsigned long stack_size)
{
unsigned long parent_tid_ptr, child_tid_ptr;
+ unsigned long orig_i1 = regs->u_regs[UREG_I1];
+ long ret;
parent_tid_ptr = regs->u_regs[UREG_I2];
child_tid_ptr = regs->u_regs[UREG_I4];
- return do_fork(clone_flags, stack_start,
- regs, stack_size,
- (int __user *) parent_tid_ptr,
- (int __user *) child_tid_ptr);
+ ret = do_fork(clone_flags, stack_start,
+ regs, stack_size,
+ (int __user *) parent_tid_ptr,
+ (int __user *) child_tid_ptr);
+
+ /* If we get an error and potentially restart the system
+ * call, we're screwed because copy_thread() clobbered
+ * the parent's %o1. So detect that case and restore it
+ * here.
+ */
+ if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
+ regs->u_regs[UREG_I1] = orig_i1;
+
+ return ret;
}
/* Copy a Sparc thread. The fork() return value conventions
diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c
index f188b5dc9fd..e995491c443 100644
--- a/arch/sparc/kernel/sys_sparc.c
+++ b/arch/sparc/kernel/sys_sparc.c
@@ -223,8 +223,7 @@ int sparc_mmap_check(unsigned long addr, unsigned long len, unsigned long flags)
{
if (ARCH_SUN4C_SUN4 &&
(len > 0x20000000 ||
- ((flags & MAP_FIXED) &&
- addr < 0xe0000000 && addr + len > 0x20000000)))
+ (addr < 0xe0000000 && addr + len > 0x20000000)))
return -EINVAL;
/* See asm-sparc/uaccess.h */
diff --git a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
index 500ac6d483a..4129c044985 100644
--- a/arch/sparc64/kernel/process.c
+++ b/arch/sparc64/kernel/process.c
@@ -503,6 +503,8 @@ asmlinkage long sparc_do_fork(unsigned long clone_flags,
unsigned long stack_size)
{
int __user *parent_tid_ptr, *child_tid_ptr;
+ unsigned long orig_i1 = regs->u_regs[UREG_I1];
+ long ret;
#ifdef CONFIG_COMPAT
if (test_thread_flag(TIF_32BIT)) {
@@ -515,9 +517,19 @@ asmlinkage long sparc_do_fork(unsigned long clone_flags,
child_tid_ptr = (int __user *) regs->u_regs[UREG_I4];
}
- return do_fork(clone_flags, stack_start,
- regs, stack_size,
- parent_tid_ptr, child_tid_ptr);
+ ret = do_fork(clone_flags, stack_start,
+ regs, stack_size,
+ parent_tid_ptr, child_tid_ptr);
+
+ /* If we get an error and potentially restart the system
+ * call, we're screwed because copy_thread() clobbered
+ * the parent's %o1. So detect that case and restore it
+ * here.
+ */
+ if ((unsigned long)ret >= -ERESTART_RESTARTBLOCK)
+ regs->u_regs[UREG_I1] = orig_i1;
+
+ return ret;
}
/* Copy a Sparc thread. The fork() return value conventions
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index 3aba47624df..0d6403a630a 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -865,21 +865,14 @@ void smp_call_function_client(int irq, struct pt_regs *regs)
void *info = call_data->info;
clear_softint(1 << irq);
-
- irq_enter();
-
- if (!call_data->wait) {
- /* let initiator proceed after getting data */
- atomic_inc(&call_data->finished);
- }
-
- func(info);
-
- irq_exit();
-
if (call_data->wait) {
/* let initiator proceed only after completion */
+ func(info);
atomic_inc(&call_data->finished);
+ } else {
+ /* let initiator proceed after getting data */
+ atomic_inc(&call_data->finished);
+ func(info);
}
}
@@ -1041,9 +1034,7 @@ void smp_receive_signal(int cpu)
void smp_receive_signal_client(int irq, struct pt_regs *regs)
{
- irq_enter();
clear_softint(1 << irq);
- irq_exit();
}
void smp_new_mmu_context_version_client(int irq, struct pt_regs *regs)
@@ -1051,8 +1042,6 @@ void smp_new_mmu_context_version_client(int irq, struct pt_regs *regs)
struct mm_struct *mm;
unsigned long flags;
- irq_enter();
-
clear_softint(1 << irq);
/* See if we need to allocate a new TLB context because
@@ -1072,8 +1061,6 @@ void smp_new_mmu_context_version_client(int irq, struct pt_regs *regs)
load_secondary_context(mm);
__flush_tlb_mm(CTX_HWBITS(mm->context),
SECONDARY_CONTEXT);
-
- irq_exit();
}
void smp_new_mmu_context_version(void)
@@ -1239,8 +1226,6 @@ void smp_penguin_jailcell(int irq, struct pt_regs *regs)
{
clear_softint(1 << irq);
- irq_enter();
-
preempt_disable();
__asm__ __volatile__("flushw");
@@ -1253,8 +1238,6 @@ void smp_penguin_jailcell(int irq, struct pt_regs *regs)
prom_world(0);
preempt_enable();
-
- irq_exit();
}
/* /proc/profile writes can call this, don't __init it please. */
diff --git a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c
index 8d4761f15fa..0dbc941f130 100644
--- a/arch/sparc64/kernel/sys_sparc.c
+++ b/arch/sparc64/kernel/sys_sparc.c
@@ -549,13 +549,13 @@ int sparc64_mmap_check(unsigned long addr, unsigned long len,
if (len >= STACK_TOP32)
return -EINVAL;
- if ((flags & MAP_FIXED) && addr > STACK_TOP32 - len)
+ if (addr > STACK_TOP32 - len)
return -EINVAL;
} else {
if (len >= VA_EXCLUDE_START)
return -EINVAL;
- if ((flags & MAP_FIXED) && invalid_64bit_range(addr, len))
+ if (invalid_64bit_range(addr, len))
return -EINVAL;
}
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index 161ce4710fe..1aa4288125f 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -236,13 +236,6 @@ asmlinkage long sys32_getegid16(void)
/* 32-bit timeval and related flotsam. */
-static long get_tv32(struct timeval *o, struct compat_timeval __user *i)
-{
- return (!access_ok(VERIFY_READ, i, sizeof(*i)) ||
- (__get_user(o->tv_sec, &i->tv_sec) |
- __get_user(o->tv_usec, &i->tv_usec)));
-}
-
static inline long put_tv32(struct compat_timeval __user *o, struct timeval *i)
{
return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
@@ -757,30 +750,6 @@ asmlinkage long sys32_settimeofday(struct compat_timeval __user *tv,
return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL);
}
-asmlinkage long sys32_utimes(char __user *filename,
- struct compat_timeval __user *tvs)
-{
- struct timespec tv[2];
-
- if (tvs) {
- struct timeval ktvs[2];
- if (get_tv32(&ktvs[0], tvs) ||
- get_tv32(&ktvs[1], 1+tvs))
- return -EFAULT;
-
- if (ktvs[0].tv_usec < 0 || ktvs[0].tv_usec >= 1000000 ||
- ktvs[1].tv_usec < 0 || ktvs[1].tv_usec >= 1000000)
- return -EINVAL;
-
- tv[0].tv_sec = ktvs[0].tv_sec;
- tv[0].tv_nsec = 1000 * ktvs[0].tv_usec;
- tv[1].tv_sec = ktvs[1].tv_sec;
- tv[1].tv_nsec = 1000 * ktvs[1].tv_usec;
- }
-
- return do_utimes(AT_FDCWD, filename, tvs ? tv : NULL, 0);
-}
-
/* These are here just in case some old sparc32 binary calls it. */
asmlinkage long sys32_pause(void)
{
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index a4fef2ba1ae..8b5282d433c 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -45,7 +45,7 @@ sys_call_table32:
/*120*/ .word compat_sys_readv, compat_sys_writev, sys32_settimeofday, sys32_fchown16, sys_fchmod
.word sys_nis_syscall, sys32_setreuid16, sys32_setregid16, sys_rename, sys_truncate
/*130*/ .word sys_ftruncate, sys_flock, compat_sys_lstat64, sys_nis_syscall, sys_nis_syscall
- .word sys_nis_syscall, sys32_mkdir, sys_rmdir, sys32_utimes, compat_sys_stat64
+ .word sys_nis_syscall, sys32_mkdir, sys_rmdir, compat_sys_utimes, compat_sys_stat64
/*140*/ .word sys32_sendfile64, sys_nis_syscall, sys32_futex, sys_gettid, compat_sys_getrlimit
.word compat_sys_setrlimit, sys_pivot_root, sys32_prctl, sys_pciconfig_read, sys_pciconfig_write
/*150*/ .word sys_nis_syscall, sys_inotify_init, sys_inotify_add_watch, sys_poll, sys_getdents64
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 4cad0b32b0a..ec3e2c72302 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -771,6 +771,9 @@ static void __init find_ramdisk(unsigned long phys_base)
initrd_end = ramdisk_image + sparc_ramdisk_size;
lmb_reserve(initrd_start, initrd_end);
+
+ initrd_start += PAGE_OFFSET;
+ initrd_end += PAGE_OFFSET;
}
#endif
}
@@ -2362,16 +2365,3 @@ void __flush_tlb_all(void)
__asm__ __volatile__("wrpr %0, 0, %%pstate"
: : "r" (pstate));
}
-
-#ifdef CONFIG_MEMORY_HOTPLUG
-
-void online_page(struct page *page)
-{
- ClearPageReserved(page);
- init_page_count(page);
- __free_page(page);
- totalram_pages++;
- num_physpages++;
-}
-
-#endif /* CONFIG_MEMORY_HOTPLUG */
diff --git a/arch/um/Makefile b/arch/um/Makefile
index 01b97c19a8b..dbeab15e7bb 100644
--- a/arch/um/Makefile
+++ b/arch/um/Makefile
@@ -77,10 +77,7 @@ include $(srctree)/$(ARCH_DIR)/Makefile-os-$(OS)
KERNEL_DEFINES = $(strip -Derrno=kernel_errno -Dsigprocmask=kernel_sigprocmask \
-Dmktime=kernel_mktime $(ARCH_KERNEL_DEFINES))
KBUILD_CFLAGS += $(KERNEL_DEFINES)
-# Disable unit-at-a-time mode on pre-gcc-4.0 compilers, it makes gcc use
-# a lot more stack due to the lack of sharing of stacklots:
-KBUILD_CFLAGS += $(shell if [ $(call cc-version) -lt 0400 ] ; then \
- echo $(call cc-option,-fno-unit-at-a-time); fi ;)
+KBUILD_CFLAGS += $(call cc-option,-fno-unit-at-a-time,)
PHONY += linux
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index 10b86e1cc65..5047490fc29 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -191,9 +191,9 @@ void line_flush_chars(struct tty_struct *tty)
line_flush_buffer(tty);
}
-void line_put_char(struct tty_struct *tty, unsigned char ch)
+int line_put_char(struct tty_struct *tty, unsigned char ch)
{
- line_write(tty, &ch, sizeof(ch));
+ return line_write(tty, &ch, sizeof(ch));
}
int line_write(struct tty_struct *tty, const unsigned char *buf, int len)
diff --git a/arch/um/include/line.h b/arch/um/include/line.h
index 1223f2c844b..979b73e6352 100644
--- a/arch/um/include/line.h
+++ b/arch/um/include/line.h
@@ -71,7 +71,7 @@ extern int line_setup(struct line *lines, unsigned int sizeof_lines,
char *init, char **error_out);
extern int line_write(struct tty_struct *tty, const unsigned char *buf,
int len);
-extern void line_put_char(struct tty_struct *tty, unsigned char ch);
+extern int line_put_char(struct tty_struct *tty, unsigned char ch);
extern void line_set_termios(struct tty_struct *tty, struct ktermios * old);
extern int line_chars_in_buffer(struct tty_struct *tty);
extern void line_flush_buffer(struct tty_struct *tty);
diff --git a/arch/x86/mm/pgtable_32.c b/arch/x86/mm/pgtable_32.c
index 9ee007be914..369cf065b6a 100644
--- a/arch/x86/mm/pgtable_32.c
+++ b/arch/x86/mm/pgtable_32.c
@@ -172,10 +172,3 @@ void reserve_top_address(unsigned long reserve)
__FIXADDR_TOP = -reserve - PAGE_SIZE;
__VMALLOC_RESERVE += reserve;
}
-
-int pmd_bad(pmd_t pmd)
-{
- WARN_ON_ONCE(pmd_bad_v1(pmd) != pmd_bad_v2(pmd));
-
- return pmd_bad_v1(pmd);
-}
diff --git a/block/blk-core.c b/block/blk-core.c
index b754a4a2f9b..2987fe47b5e 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -54,15 +54,16 @@ static DEFINE_PER_CPU(struct list_head, blk_cpu_done);
static void drive_stat_acct(struct request *rq, int new_io)
{
+ struct hd_struct *part;
int rw = rq_data_dir(rq);
if (!blk_fs_request(rq) || !rq->rq_disk)
return;
- if (!new_io) {
- __all_stat_inc(rq->rq_disk, merges[rw], rq->sector);
- } else {
- struct hd_struct *part = get_part(rq->rq_disk, rq->sector);
+ part = get_part(rq->rq_disk, rq->sector);
+ if (!new_io)
+ __all_stat_inc(rq->rq_disk, part, merges[rw], rq->sector);
+ else {
disk_round_stats(rq->rq_disk);
rq->rq_disk->in_flight++;
if (part) {
@@ -253,9 +254,11 @@ EXPORT_SYMBOL(__generic_unplug_device);
**/
void generic_unplug_device(struct request_queue *q)
{
- spin_lock_irq(q->queue_lock);
- __generic_unplug_device(q);
- spin_unlock_irq(q->queue_lock);
+ if (blk_queue_plugged(q)) {
+ spin_lock_irq(q->queue_lock);
+ __generic_unplug_device(q);
+ spin_unlock_irq(q->queue_lock);
+ }
}
EXPORT_SYMBOL(generic_unplug_device);
@@ -1536,10 +1539,11 @@ static int __end_that_request_first(struct request *req, int error,
}
if (blk_fs_request(req) && req->rq_disk) {
+ struct hd_struct *part = get_part(req->rq_disk, req->sector);
const int rw = rq_data_dir(req);
- all_stat_add(req->rq_disk, sectors[rw],
- nr_bytes >> 9, req->sector);
+ all_stat_add(req->rq_disk, part, sectors[rw],
+ nr_bytes >> 9, req->sector);
}
total_bytes = bio_nbytes = 0;
@@ -1725,8 +1729,8 @@ static void end_that_request_last(struct request *req, int error)
const int rw = rq_data_dir(req);
struct hd_struct *part = get_part(disk, req->sector);
- __all_stat_inc(disk, ios[rw], req->sector);
- __all_stat_add(disk, ticks[rw], duration, req->sector);
+ __all_stat_inc(disk, part, ios[rw], req->sector);
+ __all_stat_add(disk, part, ticks[rw], duration, req->sector);
disk_round_stats(disk);
disk->in_flight--;
if (part) {
diff --git a/block/blk-ioc.c b/block/blk-ioc.c
index e34df7c9fc3..012f065ac8e 100644
--- a/block/blk-ioc.c
+++ b/block/blk-ioc.c
@@ -41,8 +41,8 @@ int put_io_context(struct io_context *ioc)
rcu_read_lock();
if (ioc->aic && ioc->aic->dtor)
ioc->aic->dtor(ioc->aic);
- rcu_read_unlock();
cfq_dtor(ioc);
+ rcu_read_unlock();
kmem_cache_free(iocontext_cachep, ioc);
return 1;
diff --git a/block/blk-merge.c b/block/blk-merge.c
index 73b23562af2..651136aae76 100644
--- a/block/blk-merge.c
+++ b/block/blk-merge.c
@@ -149,9 +149,9 @@ static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio,
static int blk_hw_contig_segment(struct request_queue *q, struct bio *bio,
struct bio *nxt)
{
- if (unlikely(!bio_flagged(bio, BIO_SEG_VALID)))
+ if (!bio_flagged(bio, BIO_SEG_VALID))
blk_recount_segments(q, bio);
- if (unlikely(!bio_flagged(nxt, BIO_SEG_VALID)))
+ if (!bio_flagged(nxt, BIO_SEG_VALID))
blk_recount_segments(q, nxt);
if (!BIOVEC_VIRT_MERGEABLE(__BVEC_END(bio), __BVEC_START(nxt)) ||
BIOVEC_VIRT_OVERSIZE(bio->bi_hw_back_size + nxt->bi_hw_front_size))
@@ -312,9 +312,9 @@ int ll_back_merge_fn(struct request_queue *q, struct request *req,
q->last_merge = NULL;
return 0;
}
- if (unlikely(!bio_flagged(req->biotail, BIO_SEG_VALID)))
+ if (!bio_flagged(req->biotail, BIO_SEG_VALID))
blk_recount_segments(q, req->biotail);
- if (unlikely(!bio_flagged(bio, BIO_SEG_VALID)))
+ if (!bio_flagged(bio, BIO_SEG_VALID))
blk_recount_segments(q, bio);
len = req->biotail->bi_hw_back_size + bio->bi_hw_front_size;
if (BIOVEC_VIRT_MERGEABLE(__BVEC_END(req->biotail), __BVEC_START(bio))
@@ -352,9 +352,9 @@ int ll_front_merge_fn(struct request_queue *q, struct request *req,
return 0;
}
len = bio->bi_hw_back_size + req->bio->bi_hw_front_size;
- if (unlikely(!bio_flagged(bio, BIO_SEG_VALID)))
+ if (!bio_flagged(bio, BIO_SEG_VALID))
blk_recount_segments(q, bio);
- if (unlikely(!bio_flagged(req->bio, BIO_SEG_VALID)))
+ if (!bio_flagged(req->bio, BIO_SEG_VALID))
blk_recount_segments(q, req->bio);
if (BIOVEC_VIRT_MERGEABLE(__BVEC_END(bio), __BVEC_START(req->bio)) &&
!BIOVEC_VIRT_OVERSIZE(len)) {
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index e85c4013e8a..304ec73ab82 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -146,11 +146,13 @@ static ssize_t queue_nomerges_store(struct request_queue *q, const char *page,
unsigned long nm;
ssize_t ret = queue_var_store(&nm, page, count);
+ spin_lock_irq(q->queue_lock);
if (nm)
- set_bit(QUEUE_FLAG_NOMERGES, &q->queue_flags);
+ queue_flag_set(QUEUE_FLAG_NOMERGES, q);
else
- clear_bit(QUEUE_FLAG_NOMERGES, &q->queue_flags);
+ queue_flag_clear(QUEUE_FLAG_NOMERGES, q);
+ spin_unlock_irq(q->queue_lock);
return ret;
}
diff --git a/block/blk-tag.c b/block/blk-tag.c
index de64e042997..32667beb03e 100644
--- a/block/blk-tag.c
+++ b/block/blk-tag.c
@@ -70,7 +70,7 @@ void __blk_queue_free_tags(struct request_queue *q)
__blk_free_tags(bqt);
q->queue_tags = NULL;
- queue_flag_clear(QUEUE_FLAG_QUEUED, q);
+ queue_flag_clear_unlocked(QUEUE_FLAG_QUEUED, q);
}
/**
@@ -98,7 +98,7 @@ EXPORT_SYMBOL(blk_free_tags);
**/
void blk_queue_free_tags(struct request_queue *q)
{
- queue_flag_clear(QUEUE_FLAG_QUEUED, q);
+ queue_flag_clear_unlocked(QUEUE_FLAG_QUEUED, q);
}
EXPORT_SYMBOL(blk_queue_free_tags);
@@ -171,6 +171,9 @@ EXPORT_SYMBOL(blk_init_tags);
* @q: the request queue for the device
* @depth: the maximum queue depth supported
* @tags: the tag to use
+ *
+ * Queue lock must be held here if the function is called to resize an
+ * existing map.
**/
int blk_queue_init_tags(struct request_queue *q, int depth,
struct blk_queue_tag *tags)
@@ -197,7 +200,7 @@ int blk_queue_init_tags(struct request_queue *q, int depth,
* assign it, all done
*/
q->queue_tags = tags;
- queue_flag_set(QUEUE_FLAG_QUEUED, q);
+ queue_flag_set_unlocked(QUEUE_FLAG_QUEUED, q);
INIT_LIST_HEAD(&q->tag_busy_list);
return 0;
fail:
diff --git a/block/cfq-iosched.c b/block/cfq-iosched.c
index f4e1006c253..b399c62936e 100644
--- a/block/cfq-iosched.c
+++ b/block/cfq-iosched.c
@@ -1142,6 +1142,17 @@ static void cfq_put_queue(struct cfq_queue *cfqq)
kmem_cache_free(cfq_pool, cfqq);
}
+static void
+__call_for_each_cic(struct io_context *ioc,
+ void (*func)(struct io_context *, struct cfq_io_context *))
+{
+ struct cfq_io_context *cic;
+ struct hlist_node *n;
+
+ hlist_for_each_entry_rcu(cic, n, &ioc->cic_list, cic_list)
+ func(ioc, cic);
+}
+
/*
* Call func for each cic attached to this ioc.
*/
@@ -1149,12 +1160,8 @@ static void
call_for_each_cic(struct io_context *ioc,
void (*func)(struct io_context *, struct cfq_io_context *))
{
- struct cfq_io_context *cic;
- struct hlist_node *n;
-
rcu_read_lock();
- hlist_for_each_entry_rcu(cic, n, &ioc->cic_list, cic_list)
- func(ioc, cic);
+ __call_for_each_cic(ioc, func);
rcu_read_unlock();
}
@@ -1198,7 +1205,7 @@ static void cfq_free_io_context(struct io_context *ioc)
* should be ok to iterate over the known list, we will see all cic's
* since no new ones are added.
*/
- call_for_each_cic(ioc, cic_free_func);
+ __call_for_each_cic(ioc, cic_free_func);
}
static void cfq_exit_cfqq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
@@ -1296,10 +1303,10 @@ static void cfq_init_prio_data(struct cfq_queue *cfqq, struct io_context *ioc)
printk(KERN_ERR "cfq: bad prio %x\n", ioprio_class);
case IOPRIO_CLASS_NONE:
/*
- * no prio set, place us in the middle of the BE classes
+ * no prio set, inherit CPU scheduling settings
*/
cfqq->ioprio = task_nice_ioprio(tsk);
- cfqq->ioprio_class = IOPRIO_CLASS_BE;
+ cfqq->ioprio_class = task_nice_ioclass(tsk);
break;
case IOPRIO_CLASS_RT:
cfqq->ioprio = task_ioprio(ioc);
diff --git a/drivers/accessibility/Kconfig b/drivers/accessibility/Kconfig
index 1264c4b9809..ef3b65bfdd0 100644
--- a/drivers/accessibility/Kconfig
+++ b/drivers/accessibility/Kconfig
@@ -1,7 +1,17 @@
menuconfig ACCESSIBILITY
bool "Accessibility support"
---help---
- Enable a submenu where accessibility items may be enabled.
+ Accessibility handles all special kinds of hardware devices or
+ software adapters which help people with disabilities (e.g.
+ blindness) to use computers.
+
+ That includes braille devices, speech synthesis, keyboard
+ remapping, etc.
+
+ Say Y here to get to see options for accessibility.
+ This option alone does not add any kernel code.
+
+ If you say N, all options in this submenu will be skipped and disabled.
If unsure, say N.
diff --git a/drivers/ata/Kconfig b/drivers/ata/Kconfig
index 1c11df9a5f3..9bf2986a278 100644
--- a/drivers/ata/Kconfig
+++ b/drivers/ata/Kconfig
@@ -205,8 +205,8 @@ config SATA_VITESSE
If unsure, say N.
config SATA_INIC162X
- tristate "Initio 162x SATA support (HIGHLY EXPERIMENTAL)"
- depends on PCI && EXPERIMENTAL
+ tristate "Initio 162x SATA support"
+ depends on PCI
help
This option enables support for Initio 162x Serial ATA.
@@ -697,6 +697,15 @@ config PATA_SCC
If unsure, say N.
+config PATA_SCH
+ tristate "Intel SCH PATA support"
+ depends on PCI
+ help
+ This option enables support for Intel SCH PATA on the Intel
+ SCH (US15W, US15L, UL11L) series host controllers.
+
+ If unsure, say N.
+
config PATA_BF54X
tristate "Blackfin 54x ATAPI support"
depends on BF542 || BF548 || BF549
diff --git a/drivers/ata/Makefile b/drivers/ata/Makefile
index b693d829383..674965fa326 100644
--- a/drivers/ata/Makefile
+++ b/drivers/ata/Makefile
@@ -67,6 +67,7 @@ obj-$(CONFIG_PATA_SIS) += pata_sis.o
obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o
obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o
obj-$(CONFIG_PATA_SCC) += pata_scc.o
+obj-$(CONFIG_PATA_SCH) += pata_sch.o
obj-$(CONFIG_PATA_BF54X) += pata_bf54x.o
obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o
obj-$(CONFIG_PATA_OF_PLATFORM) += pata_of_platform.o
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index 8cace9aa9c0..97f83fb2ee2 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -1267,9 +1267,7 @@ static int ahci_check_ready(struct ata_link *link)
void __iomem *port_mmio = ahci_port_base(link->ap);
u8 status = readl(port_mmio + PORT_TFDATA) & 0xFF;
- if (!(status & ATA_BUSY))
- return 1;
- return 0;
+ return ata_check_ready(status);
}
static int ahci_softreset(struct ata_link *link, unsigned int *class,
diff --git a/drivers/ata/ata_generic.c b/drivers/ata/ata_generic.c
index 47aeccd52fa..75a406f5e69 100644
--- a/drivers/ata/ata_generic.c
+++ b/drivers/ata/ata_generic.c
@@ -152,6 +152,12 @@ static int ata_generic_init_one(struct pci_dev *dev, const struct pci_device_id
if (dev->vendor == PCI_VENDOR_ID_AL)
ata_pci_bmdma_clear_simplex(dev);
+ if (dev->vendor == PCI_VENDOR_ID_ATI) {
+ int rc = pcim_enable_device(dev);
+ if (rc < 0)
+ return rc;
+ pcim_pin_device(dev);
+ }
return ata_pci_sff_init_one(dev, ppi, &generic_sht, NULL);
}
diff --git a/drivers/ata/ata_piix.c b/drivers/ata/ata_piix.c
index ea2c7649d39..a9027b8fbdd 100644
--- a/drivers/ata/ata_piix.c
+++ b/drivers/ata/ata_piix.c
@@ -1348,6 +1348,8 @@ static void __devinit piix_init_sidpr(struct ata_host *host)
{
struct pci_dev *pdev = to_pci_dev(host->dev);
struct piix_host_priv *hpriv = host->private_data;
+ struct ata_device *dev0 = &host->ports[0]->link.device[0];
+ u32 scontrol;
int i;
/* check for availability */
@@ -1366,6 +1368,29 @@ static void __devinit piix_init_sidpr(struct ata_host *host)
return;
hpriv->sidpr = pcim_iomap_table(pdev)[PIIX_SIDPR_BAR];
+
+ /* SCR access via SIDPR doesn't work on some configurations.
+ * Give it a test drive by inhibiting power save modes which
+ * we'll do anyway.
+ */
+ scontrol = piix_sidpr_read(dev0, SCR_CONTROL);
+
+ /* if IPM is already 3, SCR access is probably working. Don't
+ * un-inhibit power save modes as BIOS might have inhibited
+ * them for a reason.
+ */
+ if ((scontrol & 0xf00) != 0x300) {
+ scontrol |= 0x300;
+ piix_sidpr_write(dev0, SCR_CONTROL, scontrol);
+ scontrol = piix_sidpr_read(dev0, SCR_CONTROL);
+
+ if ((scontrol & 0xf00) != 0x300) {
+ dev_printk(KERN_INFO, host->dev, "SCR access via "
+ "SIDPR is available but doesn't work\n");
+ return;
+ }
+ }
+
host->ports[0]->ops = &piix_sidpr_sata_ops;
host->ports[1]->ops = &piix_sidpr_sata_ops;
}
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index 3bc48853820..927b692d723 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -6292,6 +6292,7 @@ EXPORT_SYMBOL_GPL(ata_eh_freeze_port);
EXPORT_SYMBOL_GPL(ata_eh_thaw_port);
EXPORT_SYMBOL_GPL(ata_eh_qc_complete);
EXPORT_SYMBOL_GPL(ata_eh_qc_retry);
+EXPORT_SYMBOL_GPL(ata_eh_analyze_ncq_error);
EXPORT_SYMBOL_GPL(ata_do_eh);
EXPORT_SYMBOL_GPL(ata_std_error_handler);
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 61dcd0026c6..62e033146be 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1357,7 +1357,7 @@ static void ata_eh_analyze_serror(struct ata_link *link)
* LOCKING:
* Kernel thread context (may sleep).
*/
-static void ata_eh_analyze_ncq_error(struct ata_link *link)
+void ata_eh_analyze_ncq_error(struct ata_link *link)
{
struct ata_port *ap = link->ap;
struct ata_eh_context *ehc = &link->eh_context;
diff --git a/drivers/ata/libata-sff.c b/drivers/ata/libata-sff.c
index 2ec65a8fda7..3c2d2289f85 100644
--- a/drivers/ata/libata-sff.c
+++ b/drivers/ata/libata-sff.c
@@ -314,11 +314,7 @@ static int ata_sff_check_ready(struct ata_link *link)
{
u8 status = link->ap->ops->sff_check_status(link->ap);
- if (!(status & ATA_BUSY))
- return 1;
- if (status == 0xff)
- return -ENODEV;
- return 0;
+ return ata_check_ready(status);
}
/**
diff --git a/drivers/ata/pata_acpi.c b/drivers/ata/pata_acpi.c
index c5f91e62994..fbe60571155 100644
--- a/drivers/ata/pata_acpi.c
+++ b/drivers/ata/pata_acpi.c
@@ -259,6 +259,12 @@ static int pacpi_init_one (struct pci_dev *pdev, const struct pci_device_id *id)
.port_ops = &pacpi_ops,
};
const struct ata_port_info *ppi[] = { &info, NULL };
+ if (pdev->vendor == PCI_VENDOR_ID_ATI) {
+ int rc = pcim_enable_device(pdev);
+ if (rc < 0)
+ return rc;
+ pcim_pin_device(pdev);
+ }
return ata_pci_sff_init_one(pdev, ppi, &pacpi_sht, NULL);
}
diff --git a/drivers/ata/pata_sch.c b/drivers/ata/pata_sch.c
new file mode 100644
index 00000000000..c8cc027789f
--- /dev/null
+++ b/drivers/ata/pata_sch.c
@@ -0,0 +1,206 @@
+/*
+ * pata_sch.c - Intel SCH PATA controllers
+ *
+ * Copyright (c) 2008 Alek Du <alek.du@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 2 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; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ * Supports:
+ * Intel SCH (AF82US15W, AF82US15L, AF82UL11L) chipsets -- see spec at:
+ * http://download.intel.com/design/chipsets/embedded/datashts/319537.pdf
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <linux/dmi.h>
+
+#define DRV_NAME "pata_sch"
+#define DRV_VERSION "0.2"
+
+/* see SCH datasheet page 351 */
+enum {
+ D0TIM = 0x80, /* Device 0 Timing Register */
+ D1TIM = 0x84, /* Device 1 Timing Register */
+ PM = 0x07, /* PIO Mode Bit Mask */
+ MDM = (0x03 << 8), /* Multi-word DMA Mode Bit Mask */
+ UDM = (0x07 << 16), /* Ultra DMA Mode Bit Mask */
+ PPE = (1 << 30), /* Prefetch/Post Enable */
+ USD = (1 << 31), /* Use Synchronous DMA */
+};
+
+static int sch_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent);
+static void sch_set_piomode(struct ata_port *ap, struct ata_device *adev);
+static void sch_set_dmamode(struct ata_port *ap, struct ata_device *adev);
+
+static const struct pci_device_id sch_pci_tbl[] = {
+ /* Intel SCH PATA Controller */
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_SCH_IDE), 0 },
+ { } /* terminate list */
+};
+
+static struct pci_driver sch_pci_driver = {
+ .name = DRV_NAME,
+ .id_table = sch_pci_tbl,
+ .probe = sch_init_one,
+ .remove = ata_pci_remove_one,
+#ifdef CONFIG_PM
+ .suspend = ata_pci_device_suspend,
+ .resume = ata_pci_device_resume,
+#endif
+};
+
+static struct scsi_host_template sch_sht = {
+ ATA_BMDMA_SHT(DRV_NAME),
+};
+
+static struct ata_port_operations sch_pata_ops = {
+ .inherits = &ata_bmdma_port_ops,
+ .cable_detect = ata_cable_unknown,
+ .set_piomode = sch_set_piomode,
+ .set_dmamode = sch_set_dmamode,
+};
+
+static struct ata_port_info sch_port_info = {
+ .flags = 0,
+ .pio_mask = ATA_PIO4, /* pio0-4 */
+ .mwdma_mask = ATA_MWDMA2, /* mwdma0-2 */
+ .udma_mask = ATA_UDMA5, /* udma0-5 */
+ .port_ops = &sch_pata_ops,
+};
+
+MODULE_AUTHOR("Alek Du <alek.du@intel.com>");
+MODULE_DESCRIPTION("SCSI low-level driver for Intel SCH PATA controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, sch_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+/**
+ * sch_set_piomode - Initialize host controller PATA PIO timings
+ * @ap: Port whose timings we are configuring
+ * @adev: ATA device
+ *
+ * Set PIO mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sch_set_piomode(struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int pio = adev->pio_mode - XFER_PIO_0;
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ unsigned int port = adev->devno ? D1TIM : D0TIM;
+ unsigned int data;
+
+ pci_read_config_dword(dev, port, &data);
+ /* see SCH datasheet page 351 */
+ /* set PIO mode */
+ data &= ~(PM | PPE);
+ data |= pio;
+ /* enable PPE for block device */
+ if (adev->class == ATA_DEV_ATA)
+ data |= PPE;
+ pci_write_config_dword(dev, port, data);
+}
+
+/**
+ * sch_set_dmamode - Initialize host controller PATA DMA timings
+ * @ap: Port whose timings we are configuring
+ * @adev: ATA device
+ *
+ * Set MW/UDMA mode for device, in host controller PCI config space.
+ *
+ * LOCKING:
+ * None (inherited from caller).
+ */
+
+static void sch_set_dmamode(struct ata_port *ap, struct ata_device *adev)
+{
+ unsigned int dma_mode = adev->dma_mode;
+ struct pci_dev *dev = to_pci_dev(ap->host->dev);
+ unsigned int port = adev->devno ? D1TIM : D0TIM;
+ unsigned int data;
+
+ pci_read_config_dword(dev, port, &data);
+ /* see SCH datasheet page 351 */
+ if (dma_mode >= XFER_UDMA_0) {
+ /* enable Synchronous DMA mode */
+ data |= USD;
+ data &= ~UDM;
+ data |= (dma_mode - XFER_UDMA_0) << 16;
+ } else { /* must be MWDMA mode, since we masked SWDMA already */
+ data &= ~(USD | MDM);
+ data |= (dma_mode - XFER_MW_DMA_0) << 8;
+ }
+ pci_write_config_dword(dev, port, data);
+}
+
+/**
+ * sch_init_one - Register SCH ATA PCI device with kernel services
+ * @pdev: PCI device to register
+ * @ent: Entry in sch_pci_tbl matching with @pdev
+ *
+ * LOCKING:
+ * Inherited from PCI layer (may sleep).
+ *
+ * RETURNS:
+ * Zero on success, or -ERRNO value.
+ */
+
+static int __devinit sch_init_one(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ static int printed_version;
+ const struct ata_port_info *ppi[] = { &sch_port_info, NULL };
+ struct ata_host *host;
+ int rc;
+
+ if (!printed_version++)
+ dev_printk(KERN_DEBUG, &pdev->dev,
+ "version " DRV_VERSION "\n");
+
+ /* enable device and prepare host */
+ rc = pcim_enable_device(pdev);
+ if (rc)
+ return rc;
+ rc = ata_pci_sff_prepare_host(pdev, ppi, &host);
+ if (rc)
+ return rc;
+ pci_set_master(pdev);
+ return ata_pci_sff_activate_host(host, ata_sff_interrupt, &sch_sht);
+}
+
+static int __init sch_init(void)
+{
+ return pci_register_driver(&sch_pci_driver);
+}
+
+static void __exit sch_exit(void)
+{
+ pci_unregister_driver(&sch_pci_driver);
+}
+
+module_init(sch_init);
+module_exit(sch_exit);
diff --git a/drivers/ata/sata_inic162x.c b/drivers/ata/sata_inic162x.c
index d27bb9a2568..3ead02fe379 100644
--- a/drivers/ata/sata_inic162x.c
+++ b/drivers/ata/sata_inic162x.c
@@ -10,13 +10,33 @@
* right. Documentation is available at initio's website but it only
* documents registers (not programming model).
*
- * - ATA disks work.
- * - Hotplug works.
- * - ATAPI read works but burning doesn't. This thing is really
- * peculiar about ATAPI and I couldn't figure out how ATAPI PIO and
- * ATAPI DMA WRITE should be programmed. If you've got a clue, be
- * my guest.
- * - Both STR and STD work.
+ * This driver has interesting history. The first version was written
+ * from the documentation and a 2.4 IDE driver posted on a Taiwan
+ * company, which didn't use any IDMA features and couldn't handle
+ * LBA48. The resulting driver couldn't handle LBA48 devices either
+ * making it pretty useless.
+ *
+ * After a while, initio picked the driver up, renamed it to
+ * sata_initio162x, updated it to use IDMA for ATA DMA commands and
+ * posted it on their website. It only used ATA_PROT_DMA for IDMA and
+ * attaching both devices and issuing IDMA and !IDMA commands
+ * simultaneously broke it due to PIRQ masking interaction but it did
+ * show how to use the IDMA (ADMA + some initio specific twists)
+ * engine.
+ *
+ * Then, I picked up their changes again and here's the usable driver
+ * which uses IDMA for everything. Everything works now including
+ * LBA48, CD/DVD burning, suspend/resume and hotplug. There are some
+ * issues tho. Result Tf is not resported properly, NCQ isn't
+ * supported yet and CD/DVD writing works with DMA assisted PIO
+ * protocol (which, for native SATA devices, shouldn't cause any
+ * noticeable difference).
+ *
+ * Anyways, so, here's finally a working driver for inic162x. Enjoy!
+ *
+ * initio: If you guys wanna improve the driver regarding result TF
+ * access and other stuff, please feel free to contact me. I'll be
+ * happy to assist.
*/
#include <linux/kernel.h>
@@ -28,13 +48,19 @@
#include <scsi/scsi_device.h>
#define DRV_NAME "sata_inic162x"
-#define DRV_VERSION "0.3"
+#define DRV_VERSION "0.4"
enum {
- MMIO_BAR = 5,
+ MMIO_BAR_PCI = 5,
+ MMIO_BAR_CARDBUS = 1,
NR_PORTS = 2,
+ IDMA_CPB_TBL_SIZE = 4 * 32,
+
+ INIC_DMA_BOUNDARY = 0xffffff,
+
+ HOST_ACTRL = 0x08,
HOST_CTL = 0x7c,
HOST_STAT = 0x7e,
HOST_IRQ_STAT = 0xbc,
@@ -43,22 +69,37 @@ enum {
PORT_SIZE = 0x40,
/* registers for ATA TF operation */
- PORT_TF = 0x00,
- PORT_ALT_STAT = 0x08,
+ PORT_TF_DATA = 0x00,
+ PORT_TF_FEATURE = 0x01,
+ PORT_TF_NSECT = 0x02,
+ PORT_TF_LBAL = 0x03,
+ PORT_TF_LBAM = 0x04,
+ PORT_TF_LBAH = 0x05,
+ PORT_TF_DEVICE = 0x06,
+ PORT_TF_COMMAND = 0x07,
+ PORT_TF_ALT_STAT = 0x08,
PORT_IRQ_STAT = 0x09,
PORT_IRQ_MASK = 0x0a,
PORT_PRD_CTL = 0x0b,
PORT_PRD_ADDR = 0x0c,
PORT_PRD_XFERLEN = 0x10,
+ PORT_CPB_CPBLAR = 0x18,
+ PORT_CPB_PTQFIFO = 0x1c,
/* IDMA register */
PORT_IDMA_CTL = 0x14,
+ PORT_IDMA_STAT = 0x16,
+
+ PORT_RPQ_FIFO = 0x1e,
+ PORT_RPQ_CNT = 0x1f,
PORT_SCR = 0x20,
/* HOST_CTL bits */
HCTL_IRQOFF = (1 << 8), /* global IRQ off */
- HCTL_PWRDWN = (1 << 13), /* power down PHYs */
+ HCTL_FTHD0 = (1 << 10), /* fifo threshold 0 */
+ HCTL_FTHD1 = (1 << 11), /* fifo threshold 1*/
+ HCTL_PWRDWN = (1 << 12), /* power down PHYs */
HCTL_SOFTRST = (1 << 13), /* global reset (no phy reset) */
HCTL_RPGSEL = (1 << 15), /* register page select */
@@ -81,9 +122,7 @@ enum {
PIRQ_PENDING = (1 << 7), /* port IRQ pending (STAT only) */
PIRQ_ERR = PIRQ_OFFLINE | PIRQ_ONLINE | PIRQ_FATAL,
-
- PIRQ_MASK_DMA_READ = PIRQ_REPLY | PIRQ_ATA,
- PIRQ_MASK_OTHER = PIRQ_REPLY | PIRQ_COMPLETE,
+ PIRQ_MASK_DEFAULT = PIRQ_REPLY | PIRQ_ATA,
PIRQ_MASK_FREEZE = 0xff,
/* PORT_PRD_CTL bits */
@@ -96,20 +135,104 @@ enum {
IDMA_CTL_RST_IDMA = (1 << 5), /* reset IDMA machinary */
IDMA_CTL_GO = (1 << 7), /* IDMA mode go */
IDMA_CTL_ATA_NIEN = (1 << 8), /* ATA IRQ disable */
+
+ /* PORT_IDMA_STAT bits */
+ IDMA_STAT_PERR = (1 << 0), /* PCI ERROR MODE */
+ IDMA_STAT_CPBERR = (1 << 1), /* ADMA CPB error */
+ IDMA_STAT_LGCY = (1 << 3), /* ADMA legacy */
+ IDMA_STAT_UIRQ = (1 << 4), /* ADMA unsolicited irq */
+ IDMA_STAT_STPD = (1 << 5), /* ADMA stopped */
+ IDMA_STAT_PSD = (1 << 6), /* ADMA pause */
+ IDMA_STAT_DONE = (1 << 7), /* ADMA done */
+
+ IDMA_STAT_ERR = IDMA_STAT_PERR | IDMA_STAT_CPBERR,
+
+ /* CPB Control Flags*/
+ CPB_CTL_VALID = (1 << 0), /* CPB valid */
+ CPB_CTL_QUEUED = (1 << 1), /* queued command */
+ CPB_CTL_DATA = (1 << 2), /* data, rsvd in datasheet */
+ CPB_CTL_IEN = (1 << 3), /* PCI interrupt enable */
+ CPB_CTL_DEVDIR = (1 << 4), /* device direction control */
+
+ /* CPB Response Flags */
+ CPB_RESP_DONE = (1 << 0), /* ATA command complete */
+ CPB_RESP_REL = (1 << 1), /* ATA release */
+ CPB_RESP_IGNORED = (1 << 2), /* CPB ignored */
+ CPB_RESP_ATA_ERR = (1 << 3), /* ATA command error */
+ CPB_RESP_SPURIOUS = (1 << 4), /* ATA spurious interrupt error */
+ CPB_RESP_UNDERFLOW = (1 << 5), /* APRD deficiency length error */
+ CPB_RESP_OVERFLOW = (1 << 6), /* APRD exccess length error */
+ CPB_RESP_CPB_ERR = (1 << 7), /* CPB error flag */
+
+ /* PRD Control Flags */
+ PRD_DRAIN = (1 << 1), /* ignore data excess */
+ PRD_CDB = (1 << 2), /* atapi packet command pointer */
+ PRD_DIRECT_INTR = (1 << 3), /* direct interrupt */
+ PRD_DMA = (1 << 4), /* data transfer method */
+ PRD_WRITE = (1 << 5), /* data dir, rsvd in datasheet */
+ PRD_IOM = (1 << 6), /* io/memory transfer */
+ PRD_END = (1 << 7), /* APRD chain end */
};
+/* Comman Parameter Block */
+struct inic_cpb {
+ u8 resp_flags; /* Response Flags */
+ u8 error; /* ATA Error */
+ u8 status; /* ATA Status */
+ u8 ctl_flags; /* Control Flags */
+ __le32 len; /* Total Transfer Length */
+ __le32 prd; /* First PRD pointer */
+ u8 rsvd[4];
+ /* 16 bytes */
+ u8 feature; /* ATA Feature */
+ u8 hob_feature; /* ATA Ex. Feature */
+ u8 device; /* ATA Device/Head */
+ u8 mirctl; /* Mirror Control */
+ u8 nsect; /* ATA Sector Count */
+ u8 hob_nsect; /* ATA Ex. Sector Count */
+ u8 lbal; /* ATA Sector Number */
+ u8 hob_lbal; /* ATA Ex. Sector Number */
+ u8 lbam; /* ATA Cylinder Low */
+ u8 hob_lbam; /* ATA Ex. Cylinder Low */
+ u8 lbah; /* ATA Cylinder High */
+ u8 hob_lbah; /* ATA Ex. Cylinder High */
+ u8 command; /* ATA Command */
+ u8 ctl; /* ATA Control */
+ u8 slave_error; /* Slave ATA Error */
+ u8 slave_status; /* Slave ATA Status */
+ /* 32 bytes */
+} __packed;
+
+/* Physical Region Descriptor */
+struct inic_prd {
+ __le32 mad; /* Physical Memory Address */
+ __le16 len; /* Transfer Length */
+ u8 rsvd;
+ u8 flags; /* Control Flags */
+} __packed;
+
+struct inic_pkt {
+ struct inic_cpb cpb;
+ struct inic_prd prd[LIBATA_MAX_PRD + 1]; /* + 1 for cdb */
+ u8 cdb[ATAPI_CDB_LEN];
+} __packed;
+
struct inic_host_priv {
- u16 cached_hctl;
+ void __iomem *mmio_base;
+ u16 cached_hctl;
};
struct inic_port_priv {
- u8 dfl_prdctl;
- u8 cached_prdctl;
- u8 cached_pirq_mask;
+ struct inic_pkt *pkt;
+ dma_addr_t pkt_dma;
+ u32 *cpb_tbl;
+ dma_addr_t cpb_tbl_dma;
};
static struct scsi_host_template inic_sht = {
- ATA_BMDMA_SHT(DRV_NAME),
+ ATA_BASE_SHT(DRV_NAME),
+ .sg_tablesize = LIBATA_MAX_PRD, /* maybe it can be larger? */
+ .dma_boundary = INIC_DMA_BOUNDARY,
};
static const int scr_map[] = {
@@ -120,54 +243,34 @@ static const int scr_map[] = {
static void __iomem *inic_port_base(struct ata_port *ap)
{
- return ap->host->iomap[MMIO_BAR] + ap->port_no * PORT_SIZE;
-}
-
-static void __inic_set_pirq_mask(struct ata_port *ap, u8 mask)
-{
- void __iomem *port_base = inic_port_base(ap);
- struct inic_port_priv *pp = ap->private_data;
+ struct inic_host_priv *hpriv = ap->host->private_data;
- writeb(mask, port_base + PORT_IRQ_MASK);
- pp->cached_pirq_mask = mask;
-}
-
-static void inic_set_pirq_mask(struct ata_port *ap, u8 mask)
-{
- struct inic_port_priv *pp = ap->private_data;
-
- if (pp->cached_pirq_mask != mask)
- __inic_set_pirq_mask(ap, mask);
+ return hpriv->mmio_base + ap->port_no * PORT_SIZE;
}
static void inic_reset_port(void __iomem *port_base)
{
void __iomem *idma_ctl = port_base + PORT_IDMA_CTL;
- u16 ctl;
- ctl = readw(idma_ctl);
- ctl &= ~(IDMA_CTL_RST_IDMA | IDMA_CTL_ATA_NIEN | IDMA_CTL_GO);
+ /* stop IDMA engine */
+ readw(idma_ctl); /* flush */
+ msleep(1);
/* mask IRQ and assert reset */
- writew(ctl | IDMA_CTL_RST_IDMA | IDMA_CTL_ATA_NIEN, idma_ctl);
+ writew(IDMA_CTL_RST_IDMA, idma_ctl);
readw(idma_ctl); /* flush */
-
- /* give it some time */
msleep(1);
/* release reset */
- writew(ctl | IDMA_CTL_ATA_NIEN, idma_ctl);
+ writew(0, idma_ctl);
/* clear irq */
writeb(0xff, port_base + PORT_IRQ_STAT);
-
- /* reenable ATA IRQ, turn off IDMA mode */
- writew(ctl, idma_ctl);
}
static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
{
- void __iomem *scr_addr = ap->ioaddr.scr_addr;
+ void __iomem *scr_addr = inic_port_base(ap) + PORT_SCR;
void __iomem *addr;
if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
@@ -184,120 +287,126 @@ static int inic_scr_read(struct ata_port *ap, unsigned sc_reg, u32 *val)
static int inic_scr_write(struct ata_port *ap, unsigned sc_reg, u32 val)
{
- void __iomem *scr_addr = ap->ioaddr.scr_addr;
- void __iomem *addr;
+ void __iomem *scr_addr = inic_port_base(ap) + PORT_SCR;
if (unlikely(sc_reg >= ARRAY_SIZE(scr_map)))
return -EINVAL;
- addr = scr_addr + scr_map[sc_reg] * 4;
writel(val, scr_addr + scr_map[sc_reg] * 4);
return 0;
}
-/*
- * In TF mode, inic162x is very similar to SFF device. TF registers
- * function the same. DMA engine behaves similary using the same PRD
- * format as BMDMA but different command register, interrupt and event
- * notification methods are used. The following inic_bmdma_*()
- * functions do the impedance matching.
- */
-static void inic_bmdma_setup(struct ata_queued_cmd *qc)
+static void inic_stop_idma(struct ata_port *ap)
{
- struct ata_port *ap = qc->ap;
- struct inic_port_priv *pp = ap->private_data;
void __iomem *port_base = inic_port_base(ap);
- int rw = qc->tf.flags & ATA_TFLAG_WRITE;
-
- /* make sure device sees PRD table writes */
- wmb();
-
- /* load transfer length */
- writel(qc->nbytes, port_base + PORT_PRD_XFERLEN);
-
- /* turn on DMA and specify data direction */
- pp->cached_prdctl = pp->dfl_prdctl | PRD_CTL_DMAEN;
- if (!rw)
- pp->cached_prdctl |= PRD_CTL_WR;
- writeb(pp->cached_prdctl, port_base + PORT_PRD_CTL);
- /* issue r/w command */
- ap->ops->sff_exec_command(ap, &qc->tf);
+ readb(port_base + PORT_RPQ_FIFO);
+ readb(port_base + PORT_RPQ_CNT);
+ writew(0, port_base + PORT_IDMA_CTL);
}
-static void inic_bmdma_start(struct ata_queued_cmd *qc)
+static void inic_host_err_intr(struct ata_port *ap, u8 irq_stat, u16 idma_stat)
{
- struct ata_port *ap = qc->ap;
+ struct ata_eh_info *ehi = &ap->link.eh_info;
struct inic_port_priv *pp = ap->private_data;
- void __iomem *port_base = inic_port_base(ap);
+ struct inic_cpb *cpb = &pp->pkt->cpb;
+ bool freeze = false;
- /* start host DMA transaction */
- pp->cached_prdctl |= PRD_CTL_START;
- writeb(pp->cached_prdctl, port_base + PORT_PRD_CTL);
-}
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "irq_stat=0x%x idma_stat=0x%x",
+ irq_stat, idma_stat);
-static void inic_bmdma_stop(struct ata_queued_cmd *qc)
-{
- struct ata_port *ap = qc->ap;
- struct inic_port_priv *pp = ap->private_data;
- void __iomem *port_base = inic_port_base(ap);
+ inic_stop_idma(ap);
- /* stop DMA engine */
- writeb(pp->dfl_prdctl, port_base + PORT_PRD_CTL);
-}
+ if (irq_stat & (PIRQ_OFFLINE | PIRQ_ONLINE)) {
+ ata_ehi_push_desc(ehi, "hotplug");
+ ata_ehi_hotplugged(ehi);
+ freeze = true;
+ }
-static u8 inic_bmdma_status(struct ata_port *ap)
-{
- /* event is already verified by the interrupt handler */
- return ATA_DMA_INTR;
+ if (idma_stat & IDMA_STAT_PERR) {
+ ata_ehi_push_desc(ehi, "PCI error");
+ freeze = true;
+ }
+
+ if (idma_stat & IDMA_STAT_CPBERR) {
+ ata_ehi_push_desc(ehi, "CPB error");
+
+ if (cpb->resp_flags & CPB_RESP_IGNORED) {
+ __ata_ehi_push_desc(ehi, " ignored");
+ ehi->err_mask |= AC_ERR_INVALID;
+ freeze = true;
+ }
+
+ if (cpb->resp_flags & CPB_RESP_ATA_ERR)
+ ehi->err_mask |= AC_ERR_DEV;
+
+ if (cpb->resp_flags & CPB_RESP_SPURIOUS) {
+ __ata_ehi_push_desc(ehi, " spurious-intr");
+ ehi->err_mask |= AC_ERR_HSM;
+ freeze = true;
+ }
+
+ if (cpb->resp_flags &
+ (CPB_RESP_UNDERFLOW | CPB_RESP_OVERFLOW)) {
+ __ata_ehi_push_desc(ehi, " data-over/underflow");
+ ehi->err_mask |= AC_ERR_HSM;
+ freeze = true;
+ }
+ }
+
+ if (freeze)
+ ata_port_freeze(ap);
+ else
+ ata_port_abort(ap);
}
static void inic_host_intr(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
- struct ata_eh_info *ehi = &ap->link.eh_info;
+ struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
u8 irq_stat;
+ u16 idma_stat;
- /* fetch and clear irq */
+ /* read and clear IRQ status */
irq_stat = readb(port_base + PORT_IRQ_STAT);
writeb(irq_stat, port_base + PORT_IRQ_STAT);
+ idma_stat = readw(port_base + PORT_IDMA_STAT);
- if (likely(!(irq_stat & PIRQ_ERR))) {
- struct ata_queued_cmd *qc =
- ata_qc_from_tag(ap, ap->link.active_tag);
+ if (unlikely((irq_stat & PIRQ_ERR) || (idma_stat & IDMA_STAT_ERR)))
+ inic_host_err_intr(ap, irq_stat, idma_stat);
- if (unlikely(!qc || (qc->tf.flags & ATA_TFLAG_POLLING))) {
- ap->ops->sff_check_status(ap); /* clear ATA interrupt */
- return;
- }
+ if (unlikely(!qc))
+ goto spurious;
- if (likely(ata_sff_host_intr(ap, qc)))
- return;
+ if (likely(idma_stat & IDMA_STAT_DONE)) {
+ inic_stop_idma(ap);
- ap->ops->sff_check_status(ap); /* clear ATA interrupt */
- ata_port_printk(ap, KERN_WARNING, "unhandled "
- "interrupt, irq_stat=%x\n", irq_stat);
+ /* Depending on circumstances, device error
+ * isn't reported by IDMA, check it explicitly.
+ */
+ if (unlikely(readb(port_base + PORT_TF_COMMAND) &
+ (ATA_DF | ATA_ERR)))
+ qc->err_mask |= AC_ERR_DEV;
+
+ ata_qc_complete(qc);
return;
}
- /* error */
- ata_ehi_push_desc(ehi, "irq_stat=0x%x", irq_stat);
-
- if (irq_stat & (PIRQ_OFFLINE | PIRQ_ONLINE)) {
- ata_ehi_hotplugged(ehi);
- ata_port_freeze(ap);
- } else
- ata_port_abort(ap);
+ spurious:
+ ata_port_printk(ap, KERN_WARNING, "unhandled interrupt: "
+ "cmd=0x%x irq_stat=0x%x idma_stat=0x%x\n",
+ qc ? qc->tf.command : 0xff, irq_stat, idma_stat);
}
static irqreturn_t inic_interrupt(int irq, void *dev_instance)
{
struct ata_host *host = dev_instance;
- void __iomem *mmio_base = host->iomap[MMIO_BAR];
+ struct inic_host_priv *hpriv = host->private_data;
u16 host_irq_stat;
int i, handled = 0;;
- host_irq_stat = readw(mmio_base + HOST_IRQ_STAT);
+ host_irq_stat = readw(hpriv->mmio_base + HOST_IRQ_STAT);
if (unlikely(!(host_irq_stat & HIRQ_GLOBAL)))
goto out;
@@ -327,60 +436,173 @@ static irqreturn_t inic_interrupt(int irq, void *dev_instance)
return IRQ_RETVAL(handled);
}
+static int inic_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+ /* For some reason ATAPI_PROT_DMA doesn't work for some
+ * commands including writes and other misc ops. Use PIO
+ * protocol instead, which BTW is driven by the DMA engine
+ * anyway, so it shouldn't make much difference for native
+ * SATA devices.
+ */
+ if (atapi_cmd_type(qc->cdb[0]) == READ)
+ return 0;
+ return 1;
+}
+
+static void inic_fill_sg(struct inic_prd *prd, struct ata_queued_cmd *qc)
+{
+ struct scatterlist *sg;
+ unsigned int si;
+ u8 flags = 0;
+
+ if (qc->tf.flags & ATA_TFLAG_WRITE)
+ flags |= PRD_WRITE;
+
+ if (ata_is_dma(qc->tf.protocol))
+ flags |= PRD_DMA;
+
+ for_each_sg(qc->sg, sg, qc->n_elem, si) {
+ prd->mad = cpu_to_le32(sg_dma_address(sg));
+ prd->len = cpu_to_le16(sg_dma_len(sg));
+ prd->flags = flags;
+ prd++;
+ }
+
+ WARN_ON(!si);
+ prd[-1].flags |= PRD_END;
+}
+
+static void inic_qc_prep(struct ata_queued_cmd *qc)
+{
+ struct inic_port_priv *pp = qc->ap->private_data;
+ struct inic_pkt *pkt = pp->pkt;
+ struct inic_cpb *cpb = &pkt->cpb;
+ struct inic_prd *prd = pkt->prd;
+ bool is_atapi = ata_is_atapi(qc->tf.protocol);
+ bool is_data = ata_is_data(qc->tf.protocol);
+ unsigned int cdb_len = 0;
+
+ VPRINTK("ENTER\n");
+
+ if (is_atapi)
+ cdb_len = qc->dev->cdb_len;
+
+ /* prepare packet, based on initio driver */
+ memset(pkt, 0, sizeof(struct inic_pkt));
+
+ cpb->ctl_flags = CPB_CTL_VALID | CPB_CTL_IEN;
+ if (is_atapi || is_data)
+ cpb->ctl_flags |= CPB_CTL_DATA;
+
+ cpb->len = cpu_to_le32(qc->nbytes + cdb_len);
+ cpb->prd = cpu_to_le32(pp->pkt_dma + offsetof(struct inic_pkt, prd));
+
+ cpb->device = qc->tf.device;
+ cpb->feature = qc->tf.feature;
+ cpb->nsect = qc->tf.nsect;
+ cpb->lbal = qc->tf.lbal;
+ cpb->lbam = qc->tf.lbam;
+ cpb->lbah = qc->tf.lbah;
+
+ if (qc->tf.flags & ATA_TFLAG_LBA48) {
+ cpb->hob_feature = qc->tf.hob_feature;
+ cpb->hob_nsect = qc->tf.hob_nsect;
+ cpb->hob_lbal = qc->tf.hob_lbal;
+ cpb->hob_lbam = qc->tf.hob_lbam;
+ cpb->hob_lbah = qc->tf.hob_lbah;
+ }
+
+ cpb->command = qc->tf.command;
+ /* don't load ctl - dunno why. it's like that in the initio driver */
+
+ /* setup PRD for CDB */
+ if (is_atapi) {
+ memcpy(pkt->cdb, qc->cdb, ATAPI_CDB_LEN);
+ prd->mad = cpu_to_le32(pp->pkt_dma +
+ offsetof(struct inic_pkt, cdb));
+ prd->len = cpu_to_le16(cdb_len);
+ prd->flags = PRD_CDB | PRD_WRITE;
+ if (!is_data)
+ prd->flags |= PRD_END;
+ prd++;
+ }
+
+ /* setup sg table */
+ if (is_data)
+ inic_fill_sg(prd, qc);
+
+ pp->cpb_tbl[0] = pp->pkt_dma;
+}
+
static unsigned int inic_qc_issue(struct ata_queued_cmd *qc)
{
struct ata_port *ap = qc->ap;
+ void __iomem *port_base = inic_port_base(ap);
- /* ATA IRQ doesn't wait for DMA transfer completion and vice
- * versa. Mask IRQ selectively to detect command completion.
- * Without it, ATA DMA read command can cause data corruption.
- *
- * Something similar might be needed for ATAPI writes. I
- * tried a lot of combinations but couldn't find the solution.
- */
- if (qc->tf.protocol == ATA_PROT_DMA &&
- !(qc->tf.flags & ATA_TFLAG_WRITE))
- inic_set_pirq_mask(ap, PIRQ_MASK_DMA_READ);
- else
- inic_set_pirq_mask(ap, PIRQ_MASK_OTHER);
+ /* fire up the ADMA engine */
+ writew(HCTL_FTHD0, port_base + HOST_CTL);
+ writew(IDMA_CTL_GO, port_base + PORT_IDMA_CTL);
+ writeb(0, port_base + PORT_CPB_PTQFIFO);
+
+ return 0;
+}
+
+static void inic_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+ void __iomem *port_base = inic_port_base(ap);
+
+ tf->feature = readb(port_base + PORT_TF_FEATURE);
+ tf->nsect = readb(port_base + PORT_TF_NSECT);
+ tf->lbal = readb(port_base + PORT_TF_LBAL);
+ tf->lbam = readb(port_base + PORT_TF_LBAM);
+ tf->lbah = readb(port_base + PORT_TF_LBAH);
+ tf->device = readb(port_base + PORT_TF_DEVICE);
+ tf->command = readb(port_base + PORT_TF_COMMAND);
+}
- /* Issuing a command to yet uninitialized port locks up the
- * controller. Most of the time, this happens for the first
- * command after reset which are ATA and ATAPI IDENTIFYs.
- * Fast fail if stat is 0x7f or 0xff for those commands.
+static bool inic_qc_fill_rtf(struct ata_queued_cmd *qc)
+{
+ struct ata_taskfile *rtf = &qc->result_tf;
+ struct ata_taskfile tf;
+
+ /* FIXME: Except for status and error, result TF access
+ * doesn't work. I tried reading from BAR0/2, CPB and BAR5.
+ * None works regardless of which command interface is used.
+ * For now return true iff status indicates device error.
+ * This means that we're reporting bogus sector for RW
+ * failures. Eeekk....
*/
- if (unlikely(qc->tf.command == ATA_CMD_ID_ATA ||
- qc->tf.command == ATA_CMD_ID_ATAPI)) {
- u8 stat = ap->ops->sff_check_status(ap);
- if (stat == 0x7f || stat == 0xff)
- return AC_ERR_HSM;
- }
+ inic_tf_read(qc->ap, &tf);
- return ata_sff_qc_issue(qc);
+ if (!(tf.command & ATA_ERR))
+ return false;
+
+ rtf->command = tf.command;
+ rtf->feature = tf.feature;
+ return true;
}
static void inic_freeze(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
- __inic_set_pirq_mask(ap, PIRQ_MASK_FREEZE);
-
- ap->ops->sff_check_status(ap);
+ writeb(PIRQ_MASK_FREEZE, port_base + PORT_IRQ_MASK);
writeb(0xff, port_base + PORT_IRQ_STAT);
-
- readb(port_base + PORT_IRQ_STAT); /* flush */
}
static void inic_thaw(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
- ap->ops->sff_check_status(ap);
writeb(0xff, port_base + PORT_IRQ_STAT);
+ writeb(PIRQ_MASK_DEFAULT, port_base + PORT_IRQ_MASK);
+}
- __inic_set_pirq_mask(ap, PIRQ_MASK_OTHER);
+static int inic_check_ready(struct ata_link *link)
+{
+ void __iomem *port_base = inic_port_base(link->ap);
- readb(port_base + PORT_IRQ_STAT); /* flush */
+ return ata_check_ready(readb(port_base + PORT_TF_COMMAND));
}
/*
@@ -394,17 +616,15 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class,
void __iomem *port_base = inic_port_base(ap);
void __iomem *idma_ctl = port_base + PORT_IDMA_CTL;
const unsigned long *timing = sata_ehc_deb_timing(&link->eh_context);
- u16 val;
int rc;
/* hammer it into sane state */
inic_reset_port(port_base);
- val = readw(idma_ctl);
- writew(val | IDMA_CTL_RST_ATA, idma_ctl);
+ writew(IDMA_CTL_RST_ATA, idma_ctl);
readw(idma_ctl); /* flush */
msleep(1);
- writew(val & ~IDMA_CTL_RST_ATA, idma_ctl);
+ writew(0, idma_ctl);
rc = sata_link_resume(link, timing, deadline);
if (rc) {
@@ -418,7 +638,7 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class,
struct ata_taskfile tf;
/* wait for link to become ready */
- rc = ata_sff_wait_after_reset(link, 1, deadline);
+ rc = ata_wait_after_reset(link, deadline, inic_check_ready);
/* link occupied, -ENODEV too is an error */
if (rc) {
ata_link_printk(link, KERN_WARNING, "device not ready "
@@ -426,7 +646,7 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class,
return rc;
}
- ata_sff_tf_read(ap, &tf);
+ inic_tf_read(ap, &tf);
*class = ata_dev_classify(&tf);
}
@@ -436,18 +656,8 @@ static int inic_hardreset(struct ata_link *link, unsigned int *class,
static void inic_error_handler(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
- struct inic_port_priv *pp = ap->private_data;
- unsigned long flags;
- /* reset PIO HSM and stop DMA engine */
inic_reset_port(port_base);
-
- spin_lock_irqsave(ap->lock, flags);
- ap->hsm_task_state = HSM_ST_IDLE;
- writeb(pp->dfl_prdctl, port_base + PORT_PRD_CTL);
- spin_unlock_irqrestore(ap->lock, flags);
-
- /* PIO and DMA engines have been stopped, perform recovery */
ata_std_error_handler(ap);
}
@@ -458,26 +668,18 @@ static void inic_post_internal_cmd(struct ata_queued_cmd *qc)
inic_reset_port(inic_port_base(qc->ap));
}
-static void inic_dev_config(struct ata_device *dev)
-{
- /* inic can only handle upto LBA28 max sectors */
- if (dev->max_sectors > ATA_MAX_SECTORS)
- dev->max_sectors = ATA_MAX_SECTORS;
-
- if (dev->n_sectors >= 1 << 28) {
- ata_dev_printk(dev, KERN_ERR,
- "ERROR: This driver doesn't support LBA48 yet and may cause\n"
- " data corruption on such devices. Disabling.\n");
- ata_dev_disable(dev);
- }
-}
-
static void init_port(struct ata_port *ap)
{
void __iomem *port_base = inic_port_base(ap);
+ struct inic_port_priv *pp = ap->private_data;
- /* Setup PRD address */
+ /* clear packet and CPB table */
+ memset(pp->pkt, 0, sizeof(struct inic_pkt));
+ memset(pp->cpb_tbl, 0, IDMA_CPB_TBL_SIZE);
+
+ /* setup PRD and CPB lookup table addresses */
writel(ap->prd_dma, port_base + PORT_PRD_ADDR);
+ writel(pp->cpb_tbl_dma, port_base + PORT_CPB_CPBLAR);
}
static int inic_port_resume(struct ata_port *ap)
@@ -488,28 +690,30 @@ static int inic_port_resume(struct ata_port *ap)
static int inic_port_start(struct ata_port *ap)
{
- void __iomem *port_base = inic_port_base(ap);
+ struct device *dev = ap->host->dev;
struct inic_port_priv *pp;
- u8 tmp;
int rc;
/* alloc and initialize private data */
- pp = devm_kzalloc(ap->host->dev, sizeof(*pp), GFP_KERNEL);
+ pp = devm_kzalloc(dev, sizeof(*pp), GFP_KERNEL);
if (!pp)
return -ENOMEM;
ap->private_data = pp;
- /* default PRD_CTL value, DMAEN, WR and START off */
- tmp = readb(port_base + PORT_PRD_CTL);
- tmp &= ~(PRD_CTL_DMAEN | PRD_CTL_WR | PRD_CTL_START);
- pp->dfl_prdctl = tmp;
-
/* Alloc resources */
rc = ata_port_start(ap);
- if (rc) {
- kfree(pp);
+ if (rc)
return rc;
- }
+
+ pp->pkt = dmam_alloc_coherent(dev, sizeof(struct inic_pkt),
+ &pp->pkt_dma, GFP_KERNEL);
+ if (!pp->pkt)
+ return -ENOMEM;
+
+ pp->cpb_tbl = dmam_alloc_coherent(dev, IDMA_CPB_TBL_SIZE,
+ &pp->cpb_tbl_dma, GFP_KERNEL);
+ if (!pp->cpb_tbl)
+ return -ENOMEM;
init_port(ap);
@@ -517,21 +721,18 @@ static int inic_port_start(struct ata_port *ap)
}
static struct ata_port_operations inic_port_ops = {
- .inherits = &ata_sff_port_ops,
+ .inherits = &sata_port_ops,
- .bmdma_setup = inic_bmdma_setup,
- .bmdma_start = inic_bmdma_start,
- .bmdma_stop = inic_bmdma_stop,
- .bmdma_status = inic_bmdma_status,
+ .check_atapi_dma = inic_check_atapi_dma,
+ .qc_prep = inic_qc_prep,
.qc_issue = inic_qc_issue,
+ .qc_fill_rtf = inic_qc_fill_rtf,
.freeze = inic_freeze,
.thaw = inic_thaw,
- .softreset = ATA_OP_NULL, /* softreset is broken */
.hardreset = inic_hardreset,
.error_handler = inic_error_handler,
.post_internal_cmd = inic_post_internal_cmd,
- .dev_config = inic_dev_config,
.scr_read = inic_scr_read,
.scr_write = inic_scr_write,
@@ -541,12 +742,6 @@ static struct ata_port_operations inic_port_ops = {
};
static struct ata_port_info inic_port_info = {
- /* For some reason, ATAPI_PROT_PIO is broken on this
- * controller, and no, PIO_POLLING does't fix it. It somehow
- * manages to report the wrong ireason and ignoring ireason
- * results in machine lock up. Tell libata to always prefer
- * DMA.
- */
.flags = ATA_FLAG_SATA | ATA_FLAG_PIO_DMA,
.pio_mask = 0x1f, /* pio0-4 */
.mwdma_mask = 0x07, /* mwdma0-2 */
@@ -599,7 +794,6 @@ static int inic_pci_device_resume(struct pci_dev *pdev)
{
struct ata_host *host = dev_get_drvdata(&pdev->dev);
struct inic_host_priv *hpriv = host->private_data;
- void __iomem *mmio_base = host->iomap[MMIO_BAR];
int rc;
rc = ata_pci_device_do_resume(pdev);
@@ -607,7 +801,7 @@ static int inic_pci_device_resume(struct pci_dev *pdev)
return rc;
if (pdev->dev.power.power_state.event == PM_EVENT_SUSPEND) {
- rc = init_controller(mmio_base, hpriv->cached_hctl);
+ rc = init_controller(hpriv->mmio_base, hpriv->cached_hctl);
if (rc)
return rc;
}
@@ -625,6 +819,7 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
struct ata_host *host;
struct inic_host_priv *hpriv;
void __iomem * const *iomap;
+ int mmio_bar;
int i, rc;
if (!printed_version++)
@@ -638,38 +833,31 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
host->private_data = hpriv;
- /* acquire resources and fill host */
+ /* Acquire resources and fill host. Note that PCI and cardbus
+ * use different BARs.
+ */
rc = pcim_enable_device(pdev);
if (rc)
return rc;
- rc = pcim_iomap_regions(pdev, 0x3f, DRV_NAME);
+ if (pci_resource_flags(pdev, MMIO_BAR_PCI) & IORESOURCE_MEM)
+ mmio_bar = MMIO_BAR_PCI;
+ else
+ mmio_bar = MMIO_BAR_CARDBUS;
+
+ rc = pcim_iomap_regions(pdev, 1 << mmio_bar, DRV_NAME);
if (rc)
return rc;
host->iomap = iomap = pcim_iomap_table(pdev);
+ hpriv->mmio_base = iomap[mmio_bar];
+ hpriv->cached_hctl = readw(hpriv->mmio_base + HOST_CTL);
for (i = 0; i < NR_PORTS; i++) {
struct ata_port *ap = host->ports[i];
- struct ata_ioports *port = &ap->ioaddr;
- unsigned int offset = i * PORT_SIZE;
-
- port->cmd_addr = iomap[2 * i];
- port->altstatus_addr =
- port->ctl_addr = (void __iomem *)
- ((unsigned long)iomap[2 * i + 1] | ATA_PCI_CTL_OFS);
- port->scr_addr = iomap[MMIO_BAR] + offset + PORT_SCR;
-
- ata_sff_std_ports(port);
-
- ata_port_pbar_desc(ap, MMIO_BAR, -1, "mmio");
- ata_port_pbar_desc(ap, MMIO_BAR, offset, "port");
- ata_port_desc(ap, "cmd 0x%llx ctl 0x%llx",
- (unsigned long long)pci_resource_start(pdev, 2 * i),
- (unsigned long long)pci_resource_start(pdev, (2 * i + 1)) |
- ATA_PCI_CTL_OFS);
- }
- hpriv->cached_hctl = readw(iomap[MMIO_BAR] + HOST_CTL);
+ ata_port_pbar_desc(ap, mmio_bar, -1, "mmio");
+ ata_port_pbar_desc(ap, mmio_bar, i * PORT_SIZE, "port");
+ }
/* Set dma_mask. This devices doesn't support 64bit addressing. */
rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
@@ -698,7 +886,7 @@ static int inic_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
return rc;
}
- rc = init_controller(iomap[MMIO_BAR], hpriv->cached_hctl);
+ rc = init_controller(hpriv->mmio_base, hpriv->cached_hctl);
if (rc) {
dev_printk(KERN_ERR, &pdev->dev,
"failed to initialize controller\n");
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index 842b1a15b78..bb73b222262 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -65,6 +65,7 @@
#include <linux/platform_device.h>
#include <linux/ata_platform.h>
#include <linux/mbus.h>
+#include <linux/bitops.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_device.h>
@@ -91,9 +92,9 @@ enum {
MV_IRQ_COAL_TIME_THRESHOLD = (MV_IRQ_COAL_REG_BASE + 0xd0),
MV_SATAHC0_REG_BASE = 0x20000,
- MV_FLASH_CTL = 0x1046c,
- MV_GPIO_PORT_CTL = 0x104f0,
- MV_RESET_CFG = 0x180d8,
+ MV_FLASH_CTL_OFS = 0x1046c,
+ MV_GPIO_PORT_CTL_OFS = 0x104f0,
+ MV_RESET_CFG_OFS = 0x180d8,
MV_PCI_REG_SZ = MV_MAJOR_REG_AREA_SZ,
MV_SATAHC_REG_SZ = MV_MAJOR_REG_AREA_SZ,
@@ -147,18 +148,21 @@ enum {
/* PCI interface registers */
PCI_COMMAND_OFS = 0xc00,
+ PCI_COMMAND_MRDTRIG = (1 << 7), /* PCI Master Read Trigger */
PCI_MAIN_CMD_STS_OFS = 0xd30,
STOP_PCI_MASTER = (1 << 2),
PCI_MASTER_EMPTY = (1 << 3),
GLOB_SFT_RST = (1 << 4),
- MV_PCI_MODE = 0xd00,
+ MV_PCI_MODE_OFS = 0xd00,
+ MV_PCI_MODE_MASK = 0x30,
+
MV_PCI_EXP_ROM_BAR_CTL = 0xd2c,
MV_PCI_DISC_TIMER = 0xd04,
MV_PCI_MSI_TRIGGER = 0xc38,
MV_PCI_SERR_MASK = 0xc28,
- MV_PCI_XBAR_TMOUT = 0x1d04,
+ MV_PCI_XBAR_TMOUT_OFS = 0x1d04,
MV_PCI_ERR_LOW_ADDRESS = 0x1d40,
MV_PCI_ERR_HIGH_ADDRESS = 0x1d44,
MV_PCI_ERR_ATTRIBUTE = 0x1d48,
@@ -225,16 +229,18 @@ enum {
PHY_MODE4 = 0x314,
PHY_MODE2 = 0x330,
SATA_IFCTL_OFS = 0x344,
+ SATA_TESTCTL_OFS = 0x348,
SATA_IFSTAT_OFS = 0x34c,
VENDOR_UNIQUE_FIS_OFS = 0x35c,
- FIS_CFG_OFS = 0x360,
- FIS_CFG_SINGLE_SYNC = (1 << 16), /* SYNC on DMA activation */
+ FISCFG_OFS = 0x360,
+ FISCFG_WAIT_DEV_ERR = (1 << 8), /* wait for host on DevErr */
+ FISCFG_SINGLE_SYNC = (1 << 16), /* SYNC on DMA activation */
MV5_PHY_MODE = 0x74,
- MV5_LT_MODE = 0x30,
- MV5_PHY_CTL = 0x0C,
- SATA_INTERFACE_CFG = 0x050,
+ MV5_LTMODE_OFS = 0x30,
+ MV5_PHY_CTL_OFS = 0x0C,
+ SATA_INTERFACE_CFG_OFS = 0x050,
MV_M2_PREAMP_MASK = 0x7e0,
@@ -332,10 +338,16 @@ enum {
EDMA_CMD_OFS = 0x28, /* EDMA command register */
EDMA_EN = (1 << 0), /* enable EDMA */
EDMA_DS = (1 << 1), /* disable EDMA; self-negated */
- ATA_RST = (1 << 2), /* reset trans/link/phy */
+ EDMA_RESET = (1 << 2), /* reset eng/trans/link/phy */
+
+ EDMA_STATUS_OFS = 0x30, /* EDMA engine status */
+ EDMA_STATUS_CACHE_EMPTY = (1 << 6), /* GenIIe command cache empty */
+ EDMA_STATUS_IDLE = (1 << 7), /* GenIIe EDMA enabled/idle */
- EDMA_IORDY_TMOUT = 0x34,
- EDMA_ARB_CFG = 0x38,
+ EDMA_IORDY_TMOUT_OFS = 0x34,
+ EDMA_ARB_CFG_OFS = 0x38,
+
+ EDMA_HALTCOND_OFS = 0x60, /* GenIIe halt conditions */
GEN_II_NCQ_MAX_SECTORS = 256, /* max sects/io on Gen2 w/NCQ */
@@ -350,15 +362,19 @@ enum {
MV_HP_GEN_II = (1 << 7), /* Generation II: 60xx */
MV_HP_GEN_IIE = (1 << 8), /* Generation IIE: 6042/7042 */
MV_HP_PCIE = (1 << 9), /* PCIe bus/regs: 7042 */
+ MV_HP_CUT_THROUGH = (1 << 10), /* can use EDMA cut-through */
/* Port private flags (pp_flags) */
MV_PP_FLAG_EDMA_EN = (1 << 0), /* is EDMA engine enabled? */
MV_PP_FLAG_NCQ_EN = (1 << 1), /* is EDMA set up for NCQ? */
+ MV_PP_FLAG_FBS_EN = (1 << 2), /* is EDMA set up for FBS? */
+ MV_PP_FLAG_DELAYED_EH = (1 << 3), /* delayed dev err handling */
};
#define IS_GEN_I(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_I)
#define IS_GEN_II(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_II)
#define IS_GEN_IIE(hpriv) ((hpriv)->hp_flags & MV_HP_GEN_IIE)
+#define IS_PCIE(hpriv) ((hpriv)->hp_flags & MV_HP_PCIE)
#define HAS_PCI(host) (!((host)->ports[0]->flags & MV_FLAG_SOC))
#define WINDOW_CTRL(i) (0x20030 + ((i) << 4))
@@ -433,6 +449,7 @@ struct mv_port_priv {
unsigned int resp_idx;
u32 pp_flags;
+ unsigned int delayed_eh_pmp_map;
};
struct mv_port_signal {
@@ -479,6 +496,7 @@ static int mv5_scr_read(struct ata_port *ap, unsigned int sc_reg_in, u32 *val);
static int mv5_scr_write(struct ata_port *ap, unsigned int sc_reg_in, u32 val);
static int mv_port_start(struct ata_port *ap);
static void mv_port_stop(struct ata_port *ap);
+static int mv_qc_defer(struct ata_queued_cmd *qc);
static void mv_qc_prep(struct ata_queued_cmd *qc);
static void mv_qc_prep_iie(struct ata_queued_cmd *qc);
static unsigned int mv_qc_issue(struct ata_queued_cmd *qc);
@@ -527,6 +545,9 @@ static int mv_pmp_hardreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
static int mv_softreset(struct ata_link *link, unsigned int *class,
unsigned long deadline);
+static void mv_pmp_error_handler(struct ata_port *ap);
+static void mv_process_crpb_entries(struct ata_port *ap,
+ struct mv_port_priv *pp);
/* .sg_tablesize is (MV_MAX_SG_CT / 2) in the structures below
* because we have to allow room for worst case splitting of
@@ -548,6 +569,7 @@ static struct scsi_host_template mv6_sht = {
static struct ata_port_operations mv5_ops = {
.inherits = &ata_sff_port_ops,
+ .qc_defer = mv_qc_defer,
.qc_prep = mv_qc_prep,
.qc_issue = mv_qc_issue,
@@ -566,7 +588,6 @@ static struct ata_port_operations mv5_ops = {
static struct ata_port_operations mv6_ops = {
.inherits = &mv5_ops,
- .qc_defer = sata_pmp_qc_defer_cmd_switch,
.dev_config = mv6_dev_config,
.scr_read = mv_scr_read,
.scr_write = mv_scr_write,
@@ -574,12 +595,11 @@ static struct ata_port_operations mv6_ops = {
.pmp_hardreset = mv_pmp_hardreset,
.pmp_softreset = mv_softreset,
.softreset = mv_softreset,
- .error_handler = sata_pmp_error_handler,
+ .error_handler = mv_pmp_error_handler,
};
static struct ata_port_operations mv_iie_ops = {
.inherits = &mv6_ops,
- .qc_defer = ata_std_qc_defer, /* FIS-based switching */
.dev_config = ATA_OP_NULL,
.qc_prep = mv_qc_prep_iie,
};
@@ -875,6 +895,29 @@ static void mv_start_dma(struct ata_port *ap, void __iomem *port_mmio,
}
}
+static void mv_wait_for_edma_empty_idle(struct ata_port *ap)
+{
+ void __iomem *port_mmio = mv_ap_base(ap);
+ const u32 empty_idle = (EDMA_STATUS_CACHE_EMPTY | EDMA_STATUS_IDLE);
+ const int per_loop = 5, timeout = (15 * 1000 / per_loop);
+ int i;
+
+ /*
+ * Wait for the EDMA engine to finish transactions in progress.
+ * No idea what a good "timeout" value might be, but measurements
+ * indicate that it often requires hundreds of microseconds
+ * with two drives in-use. So we use the 15msec value above
+ * as a rough guess at what even more drives might require.
+ */
+ for (i = 0; i < timeout; ++i) {
+ u32 edma_stat = readl(port_mmio + EDMA_STATUS_OFS);
+ if ((edma_stat & empty_idle) == empty_idle)
+ break;
+ udelay(per_loop);
+ }
+ /* ata_port_printk(ap, KERN_INFO, "%s: %u+ usecs\n", __func__, i); */
+}
+
/**
* mv_stop_edma_engine - Disable eDMA engine
* @port_mmio: io base address
@@ -907,6 +950,7 @@ static int mv_stop_edma(struct ata_port *ap)
if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN))
return 0;
pp->pp_flags &= ~MV_PP_FLAG_EDMA_EN;
+ mv_wait_for_edma_empty_idle(ap);
if (mv_stop_edma_engine(port_mmio)) {
ata_port_printk(ap, KERN_ERR, "Unable to stop eDMA\n");
return -EIO;
@@ -1057,26 +1101,95 @@ static void mv6_dev_config(struct ata_device *adev)
}
}
-static void mv_config_fbs(void __iomem *port_mmio, int enable_fbs)
+static int mv_qc_defer(struct ata_queued_cmd *qc)
{
- u32 old_fcfg, new_fcfg, old_ltmode, new_ltmode;
+ struct ata_link *link = qc->dev->link;
+ struct ata_port *ap = link->ap;
+ struct mv_port_priv *pp = ap->private_data;
+
+ /*
+ * Don't allow new commands if we're in a delayed EH state
+ * for NCQ and/or FIS-based switching.
+ */
+ if (pp->pp_flags & MV_PP_FLAG_DELAYED_EH)
+ return ATA_DEFER_PORT;
/*
- * Various bit settings required for operation
- * in FIS-based switching (fbs) mode on GenIIe:
+ * If the port is completely idle, then allow the new qc.
*/
- old_fcfg = readl(port_mmio + FIS_CFG_OFS);
- old_ltmode = readl(port_mmio + LTMODE_OFS);
- if (enable_fbs) {
- new_fcfg = old_fcfg | FIS_CFG_SINGLE_SYNC;
- new_ltmode = old_ltmode | LTMODE_BIT8;
- } else { /* disable fbs */
- new_fcfg = old_fcfg & ~FIS_CFG_SINGLE_SYNC;
- new_ltmode = old_ltmode & ~LTMODE_BIT8;
- }
- if (new_fcfg != old_fcfg)
- writelfl(new_fcfg, port_mmio + FIS_CFG_OFS);
+ if (ap->nr_active_links == 0)
+ return 0;
+
+ if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
+ /*
+ * The port is operating in host queuing mode (EDMA).
+ * It can accomodate a new qc if the qc protocol
+ * is compatible with the current host queue mode.
+ */
+ if (pp->pp_flags & MV_PP_FLAG_NCQ_EN) {
+ /*
+ * The host queue (EDMA) is in NCQ mode.
+ * If the new qc is also an NCQ command,
+ * then allow the new qc.
+ */
+ if (qc->tf.protocol == ATA_PROT_NCQ)
+ return 0;
+ } else {
+ /*
+ * The host queue (EDMA) is in non-NCQ, DMA mode.
+ * If the new qc is also a non-NCQ, DMA command,
+ * then allow the new qc.
+ */
+ if (qc->tf.protocol == ATA_PROT_DMA)
+ return 0;
+ }
+ }
+ return ATA_DEFER_PORT;
+}
+
+static void mv_config_fbs(void __iomem *port_mmio, int want_ncq, int want_fbs)
+{
+ u32 new_fiscfg, old_fiscfg;
+ u32 new_ltmode, old_ltmode;
+ u32 new_haltcond, old_haltcond;
+
+ old_fiscfg = readl(port_mmio + FISCFG_OFS);
+ old_ltmode = readl(port_mmio + LTMODE_OFS);
+ old_haltcond = readl(port_mmio + EDMA_HALTCOND_OFS);
+
+ new_fiscfg = old_fiscfg & ~(FISCFG_SINGLE_SYNC | FISCFG_WAIT_DEV_ERR);
+ new_ltmode = old_ltmode & ~LTMODE_BIT8;
+ new_haltcond = old_haltcond | EDMA_ERR_DEV;
+
+ if (want_fbs) {
+ new_fiscfg = old_fiscfg | FISCFG_SINGLE_SYNC;
+ new_ltmode = old_ltmode | LTMODE_BIT8;
+ if (want_ncq)
+ new_haltcond &= ~EDMA_ERR_DEV;
+ else
+ new_fiscfg |= FISCFG_WAIT_DEV_ERR;
+ }
+
+ if (new_fiscfg != old_fiscfg)
+ writelfl(new_fiscfg, port_mmio + FISCFG_OFS);
if (new_ltmode != old_ltmode)
writelfl(new_ltmode, port_mmio + LTMODE_OFS);
+ if (new_haltcond != old_haltcond)
+ writelfl(new_haltcond, port_mmio + EDMA_HALTCOND_OFS);
+}
+
+static void mv_60x1_errata_sata25(struct ata_port *ap, int want_ncq)
+{
+ struct mv_host_priv *hpriv = ap->host->private_data;
+ u32 old, new;
+
+ /* workaround for 88SX60x1 FEr SATA#25 (part 1) */
+ old = readl(hpriv->base + MV_GPIO_PORT_CTL_OFS);
+ if (want_ncq)
+ new = old | (1 << 22);
+ else
+ new = old & ~(1 << 22);
+ if (new != old)
+ writel(new, hpriv->base + MV_GPIO_PORT_CTL_OFS);
}
static void mv_edma_cfg(struct ata_port *ap, int want_ncq)
@@ -1088,25 +1201,40 @@ static void mv_edma_cfg(struct ata_port *ap, int want_ncq)
/* set up non-NCQ EDMA configuration */
cfg = EDMA_CFG_Q_DEPTH; /* always 0x1f for *all* chips */
+ pp->pp_flags &= ~MV_PP_FLAG_FBS_EN;
if (IS_GEN_I(hpriv))
cfg |= (1 << 8); /* enab config burst size mask */
- else if (IS_GEN_II(hpriv))
+ else if (IS_GEN_II(hpriv)) {
cfg |= EDMA_CFG_RD_BRST_EXT | EDMA_CFG_WR_BUFF_LEN;
+ mv_60x1_errata_sata25(ap, want_ncq);
- else if (IS_GEN_IIE(hpriv)) {
- cfg |= (1 << 23); /* do not mask PM field in rx'd FIS */
- cfg |= (1 << 22); /* enab 4-entry host queue cache */
- cfg |= (1 << 18); /* enab early completion */
- cfg |= (1 << 17); /* enab cut-through (dis stor&forwrd) */
+ } else if (IS_GEN_IIE(hpriv)) {
+ int want_fbs = sata_pmp_attached(ap);
+ /*
+ * Possible future enhancement:
+ *
+ * The chip can use FBS with non-NCQ, if we allow it,
+ * But first we need to have the error handling in place
+ * for this mode (datasheet section 7.3.15.4.2.3).
+ * So disallow non-NCQ FBS for now.
+ */
+ want_fbs &= want_ncq;
+
+ mv_config_fbs(port_mmio, want_ncq, want_fbs);
- if (want_ncq && sata_pmp_attached(ap)) {
+ if (want_fbs) {
+ pp->pp_flags |= MV_PP_FLAG_FBS_EN;
cfg |= EDMA_CFG_EDMA_FBS; /* FIS-based switching */
- mv_config_fbs(port_mmio, 1);
- } else {
- mv_config_fbs(port_mmio, 0);
}
+
+ cfg |= (1 << 23); /* do not mask PM field in rx'd FIS */
+ cfg |= (1 << 22); /* enab 4-entry host queue cache */
+ if (HAS_PCI(ap->host))
+ cfg |= (1 << 18); /* enab early completion */
+ if (hpriv->hp_flags & MV_HP_CUT_THROUGH)
+ cfg |= (1 << 17); /* enab cut-thru (dis stor&forwrd) */
}
if (want_ncq) {
@@ -1483,25 +1611,186 @@ static struct ata_queued_cmd *mv_get_active_qc(struct ata_port *ap)
return qc;
}
-static void mv_unexpected_intr(struct ata_port *ap)
+static void mv_pmp_error_handler(struct ata_port *ap)
{
+ unsigned int pmp, pmp_map;
struct mv_port_priv *pp = ap->private_data;
- struct ata_eh_info *ehi = &ap->link.eh_info;
- char *when = "";
+ if (pp->pp_flags & MV_PP_FLAG_DELAYED_EH) {
+ /*
+ * Perform NCQ error analysis on failed PMPs
+ * before we freeze the port entirely.
+ *
+ * The failed PMPs are marked earlier by mv_pmp_eh_prep().
+ */
+ pmp_map = pp->delayed_eh_pmp_map;
+ pp->pp_flags &= ~MV_PP_FLAG_DELAYED_EH;
+ for (pmp = 0; pmp_map != 0; pmp++) {
+ unsigned int this_pmp = (1 << pmp);
+ if (pmp_map & this_pmp) {
+ struct ata_link *link = &ap->pmp_link[pmp];
+ pmp_map &= ~this_pmp;
+ ata_eh_analyze_ncq_error(link);
+ }
+ }
+ ata_port_freeze(ap);
+ }
+ sata_pmp_error_handler(ap);
+}
+
+static unsigned int mv_get_err_pmp_map(struct ata_port *ap)
+{
+ void __iomem *port_mmio = mv_ap_base(ap);
+
+ return readl(port_mmio + SATA_TESTCTL_OFS) >> 16;
+}
+
+static void mv_pmp_eh_prep(struct ata_port *ap, unsigned int pmp_map)
+{
+ struct ata_eh_info *ehi;
+ unsigned int pmp;
+
+ /*
+ * Initialize EH info for PMPs which saw device errors
+ */
+ ehi = &ap->link.eh_info;
+ for (pmp = 0; pmp_map != 0; pmp++) {
+ unsigned int this_pmp = (1 << pmp);
+ if (pmp_map & this_pmp) {
+ struct ata_link *link = &ap->pmp_link[pmp];
+
+ pmp_map &= ~this_pmp;
+ ehi = &link->eh_info;
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "dev err");
+ ehi->err_mask |= AC_ERR_DEV;
+ ehi->action |= ATA_EH_RESET;
+ ata_link_abort(link);
+ }
+ }
+}
+
+static int mv_handle_fbs_ncq_dev_err(struct ata_port *ap)
+{
+ struct mv_port_priv *pp = ap->private_data;
+ int failed_links;
+ unsigned int old_map, new_map;
+
+ /*
+ * Device error during FBS+NCQ operation:
+ *
+ * Set a port flag to prevent further I/O being enqueued.
+ * Leave the EDMA running to drain outstanding commands from this port.
+ * Perform the post-mortem/EH only when all responses are complete.
+ * Follow recovery sequence from 6042/7042 datasheet (7.3.15.4.2.2).
+ */
+ if (!(pp->pp_flags & MV_PP_FLAG_DELAYED_EH)) {
+ pp->pp_flags |= MV_PP_FLAG_DELAYED_EH;
+ pp->delayed_eh_pmp_map = 0;
+ }
+ old_map = pp->delayed_eh_pmp_map;
+ new_map = old_map | mv_get_err_pmp_map(ap);
+
+ if (old_map != new_map) {
+ pp->delayed_eh_pmp_map = new_map;
+ mv_pmp_eh_prep(ap, new_map & ~old_map);
+ }
+ failed_links = hweight16(new_map);
+
+ ata_port_printk(ap, KERN_INFO, "%s: pmp_map=%04x qc_map=%04x "
+ "failed_links=%d nr_active_links=%d\n",
+ __func__, pp->delayed_eh_pmp_map,
+ ap->qc_active, failed_links,
+ ap->nr_active_links);
+
+ if (ap->nr_active_links <= failed_links) {
+ mv_process_crpb_entries(ap, pp);
+ mv_stop_edma(ap);
+ mv_eh_freeze(ap);
+ ata_port_printk(ap, KERN_INFO, "%s: done\n", __func__);
+ return 1; /* handled */
+ }
+ ata_port_printk(ap, KERN_INFO, "%s: waiting\n", __func__);
+ return 1; /* handled */
+}
+
+static int mv_handle_fbs_non_ncq_dev_err(struct ata_port *ap)
+{
/*
- * We got a device interrupt from something that
- * was supposed to be using EDMA or polling.
+ * Possible future enhancement:
+ *
+ * FBS+non-NCQ operation is not yet implemented.
+ * See related notes in mv_edma_cfg().
+ *
+ * Device error during FBS+non-NCQ operation:
+ *
+ * We need to snapshot the shadow registers for each failed command.
+ * Follow recovery sequence from 6042/7042 datasheet (7.3.15.4.2.3).
*/
+ return 0; /* not handled */
+}
+
+static int mv_handle_dev_err(struct ata_port *ap, u32 edma_err_cause)
+{
+ struct mv_port_priv *pp = ap->private_data;
+
+ if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN))
+ return 0; /* EDMA was not active: not handled */
+ if (!(pp->pp_flags & MV_PP_FLAG_FBS_EN))
+ return 0; /* FBS was not active: not handled */
+
+ if (!(edma_err_cause & EDMA_ERR_DEV))
+ return 0; /* non DEV error: not handled */
+ edma_err_cause &= ~EDMA_ERR_IRQ_TRANSIENT;
+ if (edma_err_cause & ~(EDMA_ERR_DEV | EDMA_ERR_SELF_DIS))
+ return 0; /* other problems: not handled */
+
+ if (pp->pp_flags & MV_PP_FLAG_NCQ_EN) {
+ /*
+ * EDMA should NOT have self-disabled for this case.
+ * If it did, then something is wrong elsewhere,
+ * and we cannot handle it here.
+ */
+ if (edma_err_cause & EDMA_ERR_SELF_DIS) {
+ ata_port_printk(ap, KERN_WARNING,
+ "%s: err_cause=0x%x pp_flags=0x%x\n",
+ __func__, edma_err_cause, pp->pp_flags);
+ return 0; /* not handled */
+ }
+ return mv_handle_fbs_ncq_dev_err(ap);
+ } else {
+ /*
+ * EDMA should have self-disabled for this case.
+ * If it did not, then something is wrong elsewhere,
+ * and we cannot handle it here.
+ */
+ if (!(edma_err_cause & EDMA_ERR_SELF_DIS)) {
+ ata_port_printk(ap, KERN_WARNING,
+ "%s: err_cause=0x%x pp_flags=0x%x\n",
+ __func__, edma_err_cause, pp->pp_flags);
+ return 0; /* not handled */
+ }
+ return mv_handle_fbs_non_ncq_dev_err(ap);
+ }
+ return 0; /* not handled */
+}
+
+static void mv_unexpected_intr(struct ata_port *ap, int edma_was_enabled)
+{
+ struct ata_eh_info *ehi = &ap->link.eh_info;
+ char *when = "idle";
+
ata_ehi_clear_desc(ehi);
- if (pp->pp_flags & MV_PP_FLAG_EDMA_EN) {
- when = " while EDMA enabled";
+ if (!ap || (ap->flags & ATA_FLAG_DISABLED)) {
+ when = "disabled";
+ } else if (edma_was_enabled) {
+ when = "EDMA enabled";
} else {
struct ata_queued_cmd *qc = ata_qc_from_tag(ap, ap->link.active_tag);
if (qc && (qc->tf.flags & ATA_TFLAG_POLLING))
- when = " while polling";
+ when = "polling";
}
- ata_ehi_push_desc(ehi, "unexpected device interrupt%s", when);
+ ata_ehi_push_desc(ehi, "unexpected device interrupt while %s", when);
ehi->err_mask |= AC_ERR_OTHER;
ehi->action |= ATA_EH_RESET;
ata_port_freeze(ap);
@@ -1519,7 +1808,7 @@ static void mv_unexpected_intr(struct ata_port *ap)
* LOCKING:
* Inherited from caller.
*/
-static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
+static void mv_err_intr(struct ata_port *ap)
{
void __iomem *port_mmio = mv_ap_base(ap);
u32 edma_err_cause, eh_freeze_mask, serr = 0;
@@ -1527,24 +1816,42 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
struct mv_host_priv *hpriv = ap->host->private_data;
unsigned int action = 0, err_mask = 0;
struct ata_eh_info *ehi = &ap->link.eh_info;
-
- ata_ehi_clear_desc(ehi);
+ struct ata_queued_cmd *qc;
+ int abort = 0;
/*
- * Read and clear the err_cause bits. This won't actually
- * clear for some errors (eg. SError), but we will be doing
- * a hard reset in those cases regardless, which *will* clear it.
+ * Read and clear the SError and err_cause bits.
*/
+ sata_scr_read(&ap->link, SCR_ERROR, &serr);
+ sata_scr_write_flush(&ap->link, SCR_ERROR, serr);
+
edma_err_cause = readl(port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
writelfl(~edma_err_cause, port_mmio + EDMA_ERR_IRQ_CAUSE_OFS);
- ata_ehi_push_desc(ehi, "edma_err_cause=%08x", edma_err_cause);
+ ata_port_printk(ap, KERN_INFO, "%s: err_cause=%08x pp_flags=0x%x\n",
+ __func__, edma_err_cause, pp->pp_flags);
+
+ if (edma_err_cause & EDMA_ERR_DEV) {
+ /*
+ * Device errors during FIS-based switching operation
+ * require special handling.
+ */
+ if (mv_handle_dev_err(ap, edma_err_cause))
+ return;
+ }
+ qc = mv_get_active_qc(ap);
+ ata_ehi_clear_desc(ehi);
+ ata_ehi_push_desc(ehi, "edma_err_cause=%08x pp_flags=%08x",
+ edma_err_cause, pp->pp_flags);
/*
* All generations share these EDMA error cause bits:
*/
- if (edma_err_cause & EDMA_ERR_DEV)
+ if (edma_err_cause & EDMA_ERR_DEV) {
err_mask |= AC_ERR_DEV;
+ action |= ATA_EH_RESET;
+ ata_ehi_push_desc(ehi, "dev error");
+ }
if (edma_err_cause & (EDMA_ERR_D_PAR | EDMA_ERR_PRD_PAR |
EDMA_ERR_CRQB_PAR | EDMA_ERR_CRPB_PAR |
EDMA_ERR_INTRL_PAR)) {
@@ -1576,13 +1883,6 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
ata_ehi_push_desc(ehi, "EDMA self-disable");
}
if (edma_err_cause & EDMA_ERR_SERR) {
- /*
- * Ensure that we read our own SCR, not a pmp link SCR:
- */
- ap->ops->scr_read(ap, SCR_ERROR, &serr);
- /*
- * Don't clear SError here; leave it for libata-eh:
- */
ata_ehi_push_desc(ehi, "SError=%08x", serr);
err_mask |= AC_ERR_ATA_BUS;
action |= ATA_EH_RESET;
@@ -1602,10 +1902,29 @@ static void mv_err_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
else
ehi->err_mask |= err_mask;
- if (edma_err_cause & eh_freeze_mask)
+ if (err_mask == AC_ERR_DEV) {
+ /*
+ * Cannot do ata_port_freeze() here,
+ * because it would kill PIO access,
+ * which is needed for further diagnosis.
+ */
+ mv_eh_freeze(ap);
+ abort = 1;
+ } else if (edma_err_cause & eh_freeze_mask) {
+ /*
+ * Note to self: ata_port_freeze() calls ata_port_abort()
+ */
ata_port_freeze(ap);
- else
- ata_port_abort(ap);
+ } else {
+ abort = 1;
+ }
+
+ if (abort) {
+ if (qc)
+ ata_link_abort(qc->dev->link);
+ else
+ ata_port_abort(ap);
+ }
}
static void mv_process_crpb_response(struct ata_port *ap,
@@ -1632,8 +1951,9 @@ static void mv_process_crpb_response(struct ata_port *ap,
}
}
ata_status = edma_status >> CRPB_FLAG_STATUS_SHIFT;
- qc->err_mask |= ac_err_mask(ata_status);
- ata_qc_complete(qc);
+ if (!ac_err_mask(ata_status))
+ ata_qc_complete(qc);
+ /* else: leave it for mv_err_intr() */
} else {
ata_port_printk(ap, KERN_ERR, "%s: no qc for tag=%d\n",
__func__, tag);
@@ -1677,6 +1997,44 @@ static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp
port_mmio + EDMA_RSP_Q_OUT_PTR_OFS);
}
+static void mv_port_intr(struct ata_port *ap, u32 port_cause)
+{
+ struct mv_port_priv *pp;
+ int edma_was_enabled;
+
+ if (!ap || (ap->flags & ATA_FLAG_DISABLED)) {
+ mv_unexpected_intr(ap, 0);
+ return;
+ }
+ /*
+ * Grab a snapshot of the EDMA_EN flag setting,
+ * so that we have a consistent view for this port,
+ * even if something we call of our routines changes it.
+ */
+ pp = ap->private_data;
+ edma_was_enabled = (pp->pp_flags & MV_PP_FLAG_EDMA_EN);
+ /*
+ * Process completed CRPB response(s) before other events.
+ */
+ if (edma_was_enabled && (port_cause & DONE_IRQ)) {
+ mv_process_crpb_entries(ap, pp);
+ if (pp->pp_flags & MV_PP_FLAG_DELAYED_EH)
+ mv_handle_fbs_ncq_dev_err(ap);
+ }
+ /*
+ * Handle chip-reported errors, or continue on to handle PIO.
+ */
+ if (unlikely(port_cause & ERR_IRQ)) {
+ mv_err_intr(ap);
+ } else if (!edma_was_enabled) {
+ struct ata_queued_cmd *qc = mv_get_active_qc(ap);
+ if (qc)
+ ata_sff_host_intr(ap, qc);
+ else
+ mv_unexpected_intr(ap, edma_was_enabled);
+ }
+}
+
/**
* mv_host_intr - Handle all interrupts on the given host controller
* @host: host specific structure
@@ -1688,66 +2046,58 @@ static void mv_process_crpb_entries(struct ata_port *ap, struct mv_port_priv *pp
static int mv_host_intr(struct ata_host *host, u32 main_irq_cause)
{
struct mv_host_priv *hpriv = host->private_data;
- void __iomem *mmio = hpriv->base, *hc_mmio = NULL;
- u32 hc_irq_cause = 0;
+ void __iomem *mmio = hpriv->base, *hc_mmio;
unsigned int handled = 0, port;
for (port = 0; port < hpriv->n_ports; port++) {
struct ata_port *ap = host->ports[port];
- struct mv_port_priv *pp;
- unsigned int shift, hardport, port_cause;
- /*
- * When we move to the second hc, flag our cached
- * copies of hc_mmio (and hc_irq_cause) as invalid again.
- */
- if (port == MV_PORTS_PER_HC)
- hc_mmio = NULL;
- /*
- * Do nothing if port is not interrupting or is disabled:
- */
+ unsigned int p, shift, hardport, port_cause;
+
MV_PORT_TO_SHIFT_AND_HARDPORT(port, shift, hardport);
- port_cause = (main_irq_cause >> shift) & (DONE_IRQ | ERR_IRQ);
- if (!port_cause || !ap || (ap->flags & ATA_FLAG_DISABLED))
- continue;
/*
- * Each hc within the host has its own hc_irq_cause register.
- * We defer reading it until we know we need it, right now:
- *
- * FIXME later: we don't really need to read this register
- * (some logic changes required below if we go that way),
- * because it doesn't tell us anything new. But we do need
- * to write to it, outside the top of this loop,
- * to reset the interrupt triggers for next time.
+ * Each hc within the host has its own hc_irq_cause register,
+ * where the interrupting ports bits get ack'd.
*/
- if (!hc_mmio) {
+ if (hardport == 0) { /* first port on this hc ? */
+ u32 hc_cause = (main_irq_cause >> shift) & HC0_IRQ_PEND;
+ u32 port_mask, ack_irqs;
+ /*
+ * Skip this entire hc if nothing pending for any ports
+ */
+ if (!hc_cause) {
+ port += MV_PORTS_PER_HC - 1;
+ continue;
+ }
+ /*
+ * We don't need/want to read the hc_irq_cause register,
+ * because doing so hurts performance, and
+ * main_irq_cause already gives us everything we need.
+ *
+ * But we do have to *write* to the hc_irq_cause to ack
+ * the ports that we are handling this time through.
+ *
+ * This requires that we create a bitmap for those
+ * ports which interrupted us, and use that bitmap
+ * to ack (only) those ports via hc_irq_cause.
+ */
+ ack_irqs = 0;
+ for (p = 0; p < MV_PORTS_PER_HC; ++p) {
+ if ((port + p) >= hpriv->n_ports)
+ break;
+ port_mask = (DONE_IRQ | ERR_IRQ) << (p * 2);
+ if (hc_cause & port_mask)
+ ack_irqs |= (DMA_IRQ | DEV_IRQ) << p;
+ }
hc_mmio = mv_hc_base_from_port(mmio, port);
- hc_irq_cause = readl(hc_mmio + HC_IRQ_CAUSE_OFS);
- writelfl(~hc_irq_cause, hc_mmio + HC_IRQ_CAUSE_OFS);
+ writelfl(~ack_irqs, hc_mmio + HC_IRQ_CAUSE_OFS);
handled = 1;
}
/*
- * Process completed CRPB response(s) before other events.
- */
- pp = ap->private_data;
- if (hc_irq_cause & (DMA_IRQ << hardport)) {
- if (pp->pp_flags & MV_PP_FLAG_EDMA_EN)
- mv_process_crpb_entries(ap, pp);
- }
- /*
- * Handle chip-reported errors, or continue on to handle PIO.
+ * Handle interrupts signalled for this port:
*/
- if (unlikely(port_cause & ERR_IRQ)) {
- mv_err_intr(ap, mv_get_active_qc(ap));
- } else if (hc_irq_cause & (DEV_IRQ << hardport)) {
- if (!(pp->pp_flags & MV_PP_FLAG_EDMA_EN)) {
- struct ata_queued_cmd *qc = mv_get_active_qc(ap);
- if (qc) {
- ata_sff_host_intr(ap, qc);
- continue;
- }
- }
- mv_unexpected_intr(ap);
- }
+ port_cause = (main_irq_cause >> shift) & (DONE_IRQ | ERR_IRQ);
+ if (port_cause)
+ mv_port_intr(ap, port_cause);
}
return handled;
}
@@ -1894,7 +2244,7 @@ static void mv5_reset_bus(struct ata_host *host, void __iomem *mmio)
static void mv5_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
{
- writel(0x0fcfffff, mmio + MV_FLASH_CTL);
+ writel(0x0fcfffff, mmio + MV_FLASH_CTL_OFS);
}
static void mv5_read_preamp(struct mv_host_priv *hpriv, int idx,
@@ -1913,7 +2263,7 @@ static void mv5_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
{
u32 tmp;
- writel(0, mmio + MV_GPIO_PORT_CTL);
+ writel(0, mmio + MV_GPIO_PORT_CTL_OFS);
/* FIXME: handle MV_HP_ERRATA_50XXB2 errata */
@@ -1931,14 +2281,14 @@ static void mv5_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
int fix_apm_sq = (hpriv->hp_flags & MV_HP_ERRATA_50XXB0);
if (fix_apm_sq) {
- tmp = readl(phy_mmio + MV5_LT_MODE);
+ tmp = readl(phy_mmio + MV5_LTMODE_OFS);
tmp |= (1 << 19);
- writel(tmp, phy_mmio + MV5_LT_MODE);
+ writel(tmp, phy_mmio + MV5_LTMODE_OFS);
- tmp = readl(phy_mmio + MV5_PHY_CTL);
+ tmp = readl(phy_mmio + MV5_PHY_CTL_OFS);
tmp &= ~0x3;
tmp |= 0x1;
- writel(tmp, phy_mmio + MV5_PHY_CTL);
+ writel(tmp, phy_mmio + MV5_PHY_CTL_OFS);
}
tmp = readl(phy_mmio + MV5_PHY_MODE);
@@ -1956,11 +2306,6 @@ static void mv5_reset_hc_port(struct mv_host_priv *hpriv, void __iomem *mmio,
{
void __iomem *port_mmio = mv_port_base(mmio, port);
- /*
- * The datasheet warns against setting ATA_RST when EDMA is active
- * (but doesn't say what the problem might be). So we first try
- * to disable the EDMA engine before doing the ATA_RST operation.
- */
mv_reset_channel(hpriv, mmio, port);
ZERO(0x028); /* command */
@@ -1975,7 +2320,7 @@ static void mv5_reset_hc_port(struct mv_host_priv *hpriv, void __iomem *mmio,
ZERO(0x024); /* respq outp */
ZERO(0x020); /* respq inp */
ZERO(0x02c); /* test control */
- writel(0xbc, port_mmio + EDMA_IORDY_TMOUT);
+ writel(0xbc, port_mmio + EDMA_IORDY_TMOUT_OFS);
}
#undef ZERO
@@ -2021,13 +2366,13 @@ static void mv_reset_pci_bus(struct ata_host *host, void __iomem *mmio)
struct mv_host_priv *hpriv = host->private_data;
u32 tmp;
- tmp = readl(mmio + MV_PCI_MODE);
+ tmp = readl(mmio + MV_PCI_MODE_OFS);
tmp &= 0xff00ffff;
- writel(tmp, mmio + MV_PCI_MODE);
+ writel(tmp, mmio + MV_PCI_MODE_OFS);
ZERO(MV_PCI_DISC_TIMER);
ZERO(MV_PCI_MSI_TRIGGER);
- writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT);
+ writel(0x000100ff, mmio + MV_PCI_XBAR_TMOUT_OFS);
ZERO(PCI_HC_MAIN_IRQ_MASK_OFS);
ZERO(MV_PCI_SERR_MASK);
ZERO(hpriv->irq_cause_ofs);
@@ -2045,10 +2390,10 @@ static void mv6_reset_flash(struct mv_host_priv *hpriv, void __iomem *mmio)
mv5_reset_flash(hpriv, mmio);
- tmp = readl(mmio + MV_GPIO_PORT_CTL);
+ tmp = readl(mmio + MV_GPIO_PORT_CTL_OFS);
tmp &= 0x3;
tmp |= (1 << 5) | (1 << 6);
- writel(tmp, mmio + MV_GPIO_PORT_CTL);
+ writel(tmp, mmio + MV_GPIO_PORT_CTL_OFS);
}
/**
@@ -2121,7 +2466,7 @@ static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
void __iomem *port_mmio;
u32 tmp;
- tmp = readl(mmio + MV_RESET_CFG);
+ tmp = readl(mmio + MV_RESET_CFG_OFS);
if ((tmp & (1 << 0)) == 0) {
hpriv->signal[idx].amps = 0x7 << 8;
hpriv->signal[idx].pre = 0x1 << 5;
@@ -2137,7 +2482,7 @@ static void mv6_read_preamp(struct mv_host_priv *hpriv, int idx,
static void mv6_enable_leds(struct mv_host_priv *hpriv, void __iomem *mmio)
{
- writel(0x00000060, mmio + MV_GPIO_PORT_CTL);
+ writel(0x00000060, mmio + MV_GPIO_PORT_CTL_OFS);
}
static void mv6_phy_errata(struct mv_host_priv *hpriv, void __iomem *mmio,
@@ -2235,11 +2580,6 @@ static void mv_soc_reset_hc_port(struct mv_host_priv *hpriv,
{
void __iomem *port_mmio = mv_port_base(mmio, port);
- /*
- * The datasheet warns against setting ATA_RST when EDMA is active
- * (but doesn't say what the problem might be). So we first try
- * to disable the EDMA engine before doing the ATA_RST operation.
- */
mv_reset_channel(hpriv, mmio, port);
ZERO(0x028); /* command */
@@ -2254,7 +2594,7 @@ static void mv_soc_reset_hc_port(struct mv_host_priv *hpriv,
ZERO(0x024); /* respq outp */
ZERO(0x020); /* respq inp */
ZERO(0x02c); /* test control */
- writel(0xbc, port_mmio + EDMA_IORDY_TMOUT);
+ writel(0xbc, port_mmio + EDMA_IORDY_TMOUT_OFS);
}
#undef ZERO
@@ -2297,38 +2637,39 @@ static void mv_soc_reset_bus(struct ata_host *host, void __iomem *mmio)
return;
}
-static void mv_setup_ifctl(void __iomem *port_mmio, int want_gen2i)
+static void mv_setup_ifcfg(void __iomem *port_mmio, int want_gen2i)
{
- u32 ifctl = readl(port_mmio + SATA_INTERFACE_CFG);
+ u32 ifcfg = readl(port_mmio + SATA_INTERFACE_CFG_OFS);
- ifctl = (ifctl & 0xf7f) | 0x9b1000; /* from chip spec */
+ ifcfg = (ifcfg & 0xf7f) | 0x9b1000; /* from chip spec */
if (want_gen2i)
- ifctl |= (1 << 7); /* enable gen2i speed */
- writelfl(ifctl, port_mmio + SATA_INTERFACE_CFG);
+ ifcfg |= (1 << 7); /* enable gen2i speed */
+ writelfl(ifcfg, port_mmio + SATA_INTERFACE_CFG_OFS);
}
-/*
- * Caller must ensure that EDMA is not active,
- * by first doing mv_stop_edma() where needed.
- */
static void mv_reset_channel(struct mv_host_priv *hpriv, void __iomem *mmio,
unsigned int port_no)
{
void __iomem *port_mmio = mv_port_base(mmio, port_no);
+ /*
+ * The datasheet warns against setting EDMA_RESET when EDMA is active
+ * (but doesn't say what the problem might be). So we first try
+ * to disable the EDMA engine before doing the EDMA_RESET operation.
+ */
mv_stop_edma_engine(port_mmio);
- writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS);
+ writelfl(EDMA_RESET, port_mmio + EDMA_CMD_OFS);
if (!IS_GEN_I(hpriv)) {
- /* Enable 3.0gb/s link speed */
- mv_setup_ifctl(port_mmio, 1);
+ /* Enable 3.0gb/s link speed: this survives EDMA_RESET */
+ mv_setup_ifcfg(port_mmio, 1);
}
/*
- * Strobing ATA_RST here causes a hard reset of the SATA transport,
+ * Strobing EDMA_RESET here causes a hard reset of the SATA transport,
* link, and physical layers. It resets all SATA interface registers
* (except for SATA_INTERFACE_CFG), and issues a COMRESET to the dev.
*/
- writelfl(ATA_RST, port_mmio + EDMA_CMD_OFS);
+ writelfl(EDMA_RESET, port_mmio + EDMA_CMD_OFS);
udelay(25); /* allow reset propagation */
writelfl(0, port_mmio + EDMA_CMD_OFS);
@@ -2392,7 +2733,7 @@ static int mv_hardreset(struct ata_link *link, unsigned int *class,
sata_scr_read(link, SCR_STATUS, &sstatus);
if (!IS_GEN_I(hpriv) && ++attempts >= 5 && sstatus == 0x121) {
/* Force 1.5gb/s link speed and try again */
- mv_setup_ifctl(mv_ap_base(ap), 0);
+ mv_setup_ifcfg(mv_ap_base(ap), 0);
if (time_after(jiffies + HZ, deadline))
extra = HZ; /* only extend it once, max */
}
@@ -2493,6 +2834,34 @@ static void mv_port_init(struct ata_ioports *port, void __iomem *port_mmio)
readl(port_mmio + EDMA_ERR_IRQ_MASK_OFS));
}
+static unsigned int mv_in_pcix_mode(struct ata_host *host)
+{
+ struct mv_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->base;
+ u32 reg;
+
+ if (!HAS_PCI(host) || !IS_PCIE(hpriv))
+ return 0; /* not PCI-X capable */
+ reg = readl(mmio + MV_PCI_MODE_OFS);
+ if ((reg & MV_PCI_MODE_MASK) == 0)
+ return 0; /* conventional PCI mode */
+ return 1; /* chip is in PCI-X mode */
+}
+
+static int mv_pci_cut_through_okay(struct ata_host *host)
+{
+ struct mv_host_priv *hpriv = host->private_data;
+ void __iomem *mmio = hpriv->base;
+ u32 reg;
+
+ if (!mv_in_pcix_mode(host)) {
+ reg = readl(mmio + PCI_COMMAND_OFS);
+ if (reg & PCI_COMMAND_MRDTRIG)
+ return 0; /* not okay */
+ }
+ return 1; /* okay */
+}
+
static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
{
struct pci_dev *pdev = to_pci_dev(host->dev);
@@ -2560,7 +2929,7 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
break;
case chip_7042:
- hp_flags |= MV_HP_PCIE;
+ hp_flags |= MV_HP_PCIE | MV_HP_CUT_THROUGH;
if (pdev->vendor == PCI_VENDOR_ID_TTI &&
(pdev->device == 0x2300 || pdev->device == 0x2310))
{
@@ -2590,9 +2959,12 @@ static int mv_chip_id(struct ata_host *host, unsigned int board_idx)
" and avoid the final two gigabytes on"
" all RocketRAID BIOS initialized drives.\n");
}
+ /* drop through */
case chip_6042:
hpriv->ops = &mv6xxx_ops;
hp_flags |= MV_HP_GEN_IIE;
+ if (board_idx == chip_6042 && mv_pci_cut_through_okay(host))
+ hp_flags |= MV_HP_CUT_THROUGH;
switch (pdev->revision) {
case 0x0:
diff --git a/drivers/base/sys.c b/drivers/base/sys.c
index 4fbb56bcb1e..358bb0be3c0 100644
--- a/drivers/base/sys.c
+++ b/drivers/base/sys.c
@@ -175,8 +175,7 @@ int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv)
}
/* Check whether this driver has already been added to a class. */
- if ((drv->entry.next != drv->entry.prev) ||
- (drv->entry.next != NULL)) {
+ if (drv->entry.next && !list_empty(&drv->entry)) {
printk(KERN_WARNING "sysdev: class %s: driver (%p) has already"
" been registered to a class, something is wrong, but "
"will forge on!\n", cls->name, drv);
diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c
index 8fc429cf82b..41f818be2f7 100644
--- a/drivers/block/aoe/aoecmd.c
+++ b/drivers/block/aoe/aoecmd.c
@@ -755,11 +755,13 @@ diskstats(struct gendisk *disk, struct bio *bio, ulong duration, sector_t sector
{
unsigned long n_sect = bio->bi_size >> 9;
const int rw = bio_data_dir(bio);
+ struct hd_struct *part;
- all_stat_inc(disk, ios[rw], sector);
- all_stat_add(disk, ticks[rw], duration, sector);
- all_stat_add(disk, sectors[rw], n_sect, sector);
- all_stat_add(disk, io_ticks, duration, sector);
+ part = get_part(disk, sector);
+ all_stat_inc(disk, part, ios[rw], sector);
+ all_stat_add(disk, part, ticks[rw], duration, sector);
+ all_stat_add(disk, part, sectors[rw], n_sect, sector);
+ all_stat_add(disk, part, io_ticks, duration, sector);
}
void
diff --git a/drivers/char/sx.c b/drivers/char/sx.c
index f39f6fd8935..b1a7a8cb65e 100644
--- a/drivers/char/sx.c
+++ b/drivers/char/sx.c
@@ -970,7 +970,8 @@ static int sx_set_real_termios(void *ptr)
sx_write_channel_byte(port, hi_mask, 0x1f);
break;
default:
- printk(KERN_INFO "sx: Invalid wordsize: %u\n", CFLAG & CSIZE);
+ printk(KERN_INFO "sx: Invalid wordsize: %u\n",
+ (unsigned int)CFLAG & CSIZE);
break;
}
@@ -997,7 +998,8 @@ static int sx_set_real_termios(void *ptr)
set_bit(TTY_HW_COOK_IN, &port->gs.tty->flags);
}
sx_dprintk(SX_DEBUG_TERMIOS, "iflags: %x(%d) ",
- port->gs.tty->termios->c_iflag, I_OTHER(port->gs.tty));
+ (unsigned int)port->gs.tty->termios->c_iflag,
+ I_OTHER(port->gs.tty));
/* Tell line discipline whether we will do output cooking.
* If OPOST is set and no other output flags are set then we can do output
@@ -1010,7 +1012,8 @@ static int sx_set_real_termios(void *ptr)
clear_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);
}
sx_dprintk(SX_DEBUG_TERMIOS, "oflags: %x(%d)\n",
- port->gs.tty->termios->c_oflag, O_OTHER(port->gs.tty));
+ (unsigned int)port->gs.tty->termios->c_oflag,
+ O_OTHER(port->gs.tty));
/* port->c_dcd = sx_get_CD (port); */
func_exit();
return 0;
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index e458b08139a..fa1ffbf2c62 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -2742,6 +2742,10 @@ static int con_open(struct tty_struct *tty, struct file *filp)
tty->winsize.ws_row = vc_cons[currcons].d->vc_rows;
tty->winsize.ws_col = vc_cons[currcons].d->vc_cols;
}
+ if (vc->vc_utf)
+ tty->termios->c_iflag |= IUTF8;
+ else
+ tty->termios->c_iflag &= ~IUTF8;
release_console_sem();
vcs_make_sysfs(tty);
return ret;
@@ -2918,6 +2922,8 @@ int __init vty_init(void)
console_driver->minor_start = 1;
console_driver->type = TTY_DRIVER_TYPE_CONSOLE;
console_driver->init_termios = tty_std_termios;
+ if (default_utf8)
+ console_driver->init_termios.c_iflag |= IUTF8;
console_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
tty_set_operations(console_driver, &con_ops);
if (tty_register_driver(console_driver))
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.c b/drivers/infiniband/hw/cxgb3/cxio_hal.c
index 5fd8506a865..ebf9d3043f8 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_hal.c
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.c
@@ -588,7 +588,7 @@ static int cxio_hal_destroy_ctrl_qp(struct cxio_rdev *rdev_p)
* caller aquires the ctrl_qp lock before the call
*/
static int cxio_hal_ctrl_qp_write_mem(struct cxio_rdev *rdev_p, u32 addr,
- u32 len, void *data, int completion)
+ u32 len, void *data)
{
u32 i, nr_wqe, copy_len;
u8 *copy_data;
@@ -624,7 +624,7 @@ static int cxio_hal_ctrl_qp_write_mem(struct cxio_rdev *rdev_p, u32 addr,
flag = 0;
if (i == (nr_wqe - 1)) {
/* last WQE */
- flag = completion ? T3_COMPLETION_FLAG : 0;
+ flag = T3_COMPLETION_FLAG;
if (len % 32)
utx_len = len / 32 + 1;
else
@@ -683,21 +683,20 @@ static int cxio_hal_ctrl_qp_write_mem(struct cxio_rdev *rdev_p, u32 addr,
return 0;
}
-/* IN: stag key, pdid, perm, zbva, to, len, page_size, pbl, and pbl_size
- * OUT: stag index, actual pbl_size, pbl_addr allocated.
+/* IN: stag key, pdid, perm, zbva, to, len, page_size, pbl_size and pbl_addr
+ * OUT: stag index
* TBD: shared memory region support
*/
static int __cxio_tpt_op(struct cxio_rdev *rdev_p, u32 reset_tpt_entry,
u32 *stag, u8 stag_state, u32 pdid,
enum tpt_mem_type type, enum tpt_mem_perm perm,
- u32 zbva, u64 to, u32 len, u8 page_size, __be64 *pbl,
- u32 *pbl_size, u32 *pbl_addr)
+ u32 zbva, u64 to, u32 len, u8 page_size,
+ u32 pbl_size, u32 pbl_addr)
{
int err;
struct tpt_entry tpt;
u32 stag_idx;
u32 wptr;
- int rereg = (*stag != T3_STAG_UNSET);
stag_state = stag_state > 0;
stag_idx = (*stag) >> 8;
@@ -711,30 +710,8 @@ static int __cxio_tpt_op(struct cxio_rdev *rdev_p, u32 reset_tpt_entry,
PDBG("%s stag_state 0x%0x type 0x%0x pdid 0x%0x, stag_idx 0x%x\n",
__func__, stag_state, type, pdid, stag_idx);
- if (reset_tpt_entry)
- cxio_hal_pblpool_free(rdev_p, *pbl_addr, *pbl_size << 3);
- else if (!rereg) {
- *pbl_addr = cxio_hal_pblpool_alloc(rdev_p, *pbl_size << 3);
- if (!*pbl_addr) {
- return -ENOMEM;
- }
- }
-
mutex_lock(&rdev_p->ctrl_qp.lock);
- /* write PBL first if any - update pbl only if pbl list exist */
- if (pbl) {
-
- PDBG("%s *pdb_addr 0x%x, pbl_base 0x%x, pbl_size %d\n",
- __func__, *pbl_addr, rdev_p->rnic_info.pbl_base,
- *pbl_size);
- err = cxio_hal_ctrl_qp_write_mem(rdev_p,
- (*pbl_addr >> 5),
- (*pbl_size << 3), pbl, 0);
- if (err)
- goto ret;
- }
-
/* write TPT entry */
if (reset_tpt_entry)
memset(&tpt, 0, sizeof(tpt));
@@ -749,23 +726,23 @@ static int __cxio_tpt_op(struct cxio_rdev *rdev_p, u32 reset_tpt_entry,
V_TPT_ADDR_TYPE((zbva ? TPT_ZBTO : TPT_VATO)) |
V_TPT_PAGE_SIZE(page_size));
tpt.rsvd_pbl_addr = reset_tpt_entry ? 0 :
- cpu_to_be32(V_TPT_PBL_ADDR(PBL_OFF(rdev_p, *pbl_addr)>>3));
+ cpu_to_be32(V_TPT_PBL_ADDR(PBL_OFF(rdev_p, pbl_addr)>>3));
tpt.len = cpu_to_be32(len);
tpt.va_hi = cpu_to_be32((u32) (to >> 32));
tpt.va_low_or_fbo = cpu_to_be32((u32) (to & 0xFFFFFFFFULL));
tpt.rsvd_bind_cnt_or_pstag = 0;
tpt.rsvd_pbl_size = reset_tpt_entry ? 0 :
- cpu_to_be32(V_TPT_PBL_SIZE((*pbl_size) >> 2));
+ cpu_to_be32(V_TPT_PBL_SIZE(pbl_size >> 2));
}
err = cxio_hal_ctrl_qp_write_mem(rdev_p,
stag_idx +
(rdev_p->rnic_info.tpt_base >> 5),
- sizeof(tpt), &tpt, 1);
+ sizeof(tpt), &tpt);
/* release the stag index to free pool */
if (reset_tpt_entry)
cxio_hal_put_stag(rdev_p->rscp, stag_idx);
-ret:
+
wptr = rdev_p->ctrl_qp.wptr;
mutex_unlock(&rdev_p->ctrl_qp.lock);
if (!err)
@@ -776,44 +753,67 @@ ret:
return err;
}
+int cxio_write_pbl(struct cxio_rdev *rdev_p, __be64 *pbl,
+ u32 pbl_addr, u32 pbl_size)
+{
+ u32 wptr;
+ int err;
+
+ PDBG("%s *pdb_addr 0x%x, pbl_base 0x%x, pbl_size %d\n",
+ __func__, pbl_addr, rdev_p->rnic_info.pbl_base,
+ pbl_size);
+
+ mutex_lock(&rdev_p->ctrl_qp.lock);
+ err = cxio_hal_ctrl_qp_write_mem(rdev_p, pbl_addr >> 5, pbl_size << 3,
+ pbl);
+ wptr = rdev_p->ctrl_qp.wptr;
+ mutex_unlock(&rdev_p->ctrl_qp.lock);
+ if (err)
+ return err;
+
+ if (wait_event_interruptible(rdev_p->ctrl_qp.waitq,
+ SEQ32_GE(rdev_p->ctrl_qp.rptr,
+ wptr)))
+ return -ERESTARTSYS;
+
+ return 0;
+}
+
int cxio_register_phys_mem(struct cxio_rdev *rdev_p, u32 *stag, u32 pdid,
enum tpt_mem_perm perm, u32 zbva, u64 to, u32 len,
- u8 page_size, __be64 *pbl, u32 *pbl_size,
- u32 *pbl_addr)
+ u8 page_size, u32 pbl_size, u32 pbl_addr)
{
*stag = T3_STAG_UNSET;
return __cxio_tpt_op(rdev_p, 0, stag, 1, pdid, TPT_NON_SHARED_MR, perm,
- zbva, to, len, page_size, pbl, pbl_size, pbl_addr);
+ zbva, to, len, page_size, pbl_size, pbl_addr);
}
int cxio_reregister_phys_mem(struct cxio_rdev *rdev_p, u32 *stag, u32 pdid,
enum tpt_mem_perm perm, u32 zbva, u64 to, u32 len,
- u8 page_size, __be64 *pbl, u32 *pbl_size,
- u32 *pbl_addr)
+ u8 page_size, u32 pbl_size, u32 pbl_addr)
{
return __cxio_tpt_op(rdev_p, 0, stag, 1, pdid, TPT_NON_SHARED_MR, perm,
- zbva, to, len, page_size, pbl, pbl_size, pbl_addr);
+ zbva, to, len, page_size, pbl_size, pbl_addr);
}
int cxio_dereg_mem(struct cxio_rdev *rdev_p, u32 stag, u32 pbl_size,
u32 pbl_addr)
{
- return __cxio_tpt_op(rdev_p, 1, &stag, 0, 0, 0, 0, 0, 0ULL, 0, 0, NULL,
- &pbl_size, &pbl_addr);
+ return __cxio_tpt_op(rdev_p, 1, &stag, 0, 0, 0, 0, 0, 0ULL, 0, 0,
+ pbl_size, pbl_addr);
}
int cxio_allocate_window(struct cxio_rdev *rdev_p, u32 * stag, u32 pdid)
{
- u32 pbl_size = 0;
*stag = T3_STAG_UNSET;
return __cxio_tpt_op(rdev_p, 0, stag, 0, pdid, TPT_MW, 0, 0, 0ULL, 0, 0,
- NULL, &pbl_size, NULL);
+ 0, 0);
}
int cxio_deallocate_window(struct cxio_rdev *rdev_p, u32 stag)
{
- return __cxio_tpt_op(rdev_p, 1, &stag, 0, 0, 0, 0, 0, 0ULL, 0, 0, NULL,
- NULL, NULL);
+ return __cxio_tpt_op(rdev_p, 1, &stag, 0, 0, 0, 0, 0, 0ULL, 0, 0,
+ 0, 0);
}
int cxio_rdma_init(struct cxio_rdev *rdev_p, struct t3_rdma_init_attr *attr)
diff --git a/drivers/infiniband/hw/cxgb3/cxio_hal.h b/drivers/infiniband/hw/cxgb3/cxio_hal.h
index 69ab08ebc68..6e128f6bab0 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_hal.h
+++ b/drivers/infiniband/hw/cxgb3/cxio_hal.h
@@ -154,14 +154,14 @@ int cxio_create_qp(struct cxio_rdev *rdev, u32 kernel_domain, struct t3_wq *wq,
int cxio_destroy_qp(struct cxio_rdev *rdev, struct t3_wq *wq,
struct cxio_ucontext *uctx);
int cxio_peek_cq(struct t3_wq *wr, struct t3_cq *cq, int opcode);
+int cxio_write_pbl(struct cxio_rdev *rdev_p, __be64 *pbl,
+ u32 pbl_addr, u32 pbl_size);
int cxio_register_phys_mem(struct cxio_rdev *rdev, u32 * stag, u32 pdid,
enum tpt_mem_perm perm, u32 zbva, u64 to, u32 len,
- u8 page_size, __be64 *pbl, u32 *pbl_size,
- u32 *pbl_addr);
+ u8 page_size, u32 pbl_size, u32 pbl_addr);
int cxio_reregister_phys_mem(struct cxio_rdev *rdev, u32 * stag, u32 pdid,
enum tpt_mem_perm perm, u32 zbva, u64 to, u32 len,
- u8 page_size, __be64 *pbl, u32 *pbl_size,
- u32 *pbl_addr);
+ u8 page_size, u32 pbl_size, u32 pbl_addr);
int cxio_dereg_mem(struct cxio_rdev *rdev, u32 stag, u32 pbl_size,
u32 pbl_addr);
int cxio_allocate_window(struct cxio_rdev *rdev, u32 * stag, u32 pdid);
diff --git a/drivers/infiniband/hw/cxgb3/cxio_resource.c b/drivers/infiniband/hw/cxgb3/cxio_resource.c
index 45ed4f25ef7..bd233c08765 100644
--- a/drivers/infiniband/hw/cxgb3/cxio_resource.c
+++ b/drivers/infiniband/hw/cxgb3/cxio_resource.c
@@ -250,7 +250,6 @@ void cxio_hal_destroy_resource(struct cxio_hal_resource *rscp)
*/
#define MIN_PBL_SHIFT 8 /* 256B == min PBL size (32 entries) */
-#define PBL_CHUNK 2*1024*1024
u32 cxio_hal_pblpool_alloc(struct cxio_rdev *rdev_p, int size)
{
@@ -267,14 +266,35 @@ void cxio_hal_pblpool_free(struct cxio_rdev *rdev_p, u32 addr, int size)
int cxio_hal_pblpool_create(struct cxio_rdev *rdev_p)
{
- unsigned long i;
+ unsigned pbl_start, pbl_chunk;
+
rdev_p->pbl_pool = gen_pool_create(MIN_PBL_SHIFT, -1);
- if (rdev_p->pbl_pool)
- for (i = rdev_p->rnic_info.pbl_base;
- i <= rdev_p->rnic_info.pbl_top - PBL_CHUNK + 1;
- i += PBL_CHUNK)
- gen_pool_add(rdev_p->pbl_pool, i, PBL_CHUNK, -1);
- return rdev_p->pbl_pool ? 0 : -ENOMEM;
+ if (!rdev_p->pbl_pool)
+ return -ENOMEM;
+
+ pbl_start = rdev_p->rnic_info.pbl_base;
+ pbl_chunk = rdev_p->rnic_info.pbl_top - pbl_start + 1;
+
+ while (pbl_start < rdev_p->rnic_info.pbl_top) {
+ pbl_chunk = min(rdev_p->rnic_info.pbl_top - pbl_start + 1,
+ pbl_chunk);
+ if (gen_pool_add(rdev_p->pbl_pool, pbl_start, pbl_chunk, -1)) {
+ PDBG("%s failed to add PBL chunk (%x/%x)\n",
+ __func__, pbl_start, pbl_chunk);
+ if (pbl_chunk <= 1024 << MIN_PBL_SHIFT) {
+ printk(KERN_WARNING MOD "%s: Failed to add all PBL chunks (%x/%x)\n",
+ __func__, pbl_start, rdev_p->rnic_info.pbl_top - pbl_start);
+ return 0;
+ }
+ pbl_chunk >>= 1;
+ } else {
+ PDBG("%s added PBL chunk (%x/%x)\n",
+ __func__, pbl_start, pbl_chunk);
+ pbl_start += pbl_chunk;
+ }
+ }
+
+ return 0;
}
void cxio_hal_pblpool_destroy(struct cxio_rdev *rdev_p)
diff --git a/drivers/infiniband/hw/cxgb3/iwch_mem.c b/drivers/infiniband/hw/cxgb3/iwch_mem.c
index 58c3d61bcd1..ec49a5cbdeb 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_mem.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_mem.c
@@ -35,17 +35,26 @@
#include <rdma/ib_verbs.h>
#include "cxio_hal.h"
+#include "cxio_resource.h"
#include "iwch.h"
#include "iwch_provider.h"
-int iwch_register_mem(struct iwch_dev *rhp, struct iwch_pd *php,
- struct iwch_mr *mhp,
- int shift,
- __be64 *page_list)
+static void iwch_finish_mem_reg(struct iwch_mr *mhp, u32 stag)
{
- u32 stag;
u32 mmid;
+ mhp->attr.state = 1;
+ mhp->attr.stag = stag;
+ mmid = stag >> 8;
+ mhp->ibmr.rkey = mhp->ibmr.lkey = stag;
+ insert_handle(mhp->rhp, &mhp->rhp->mmidr, mhp, mmid);
+ PDBG("%s mmid 0x%x mhp %p\n", __func__, mmid, mhp);
+}
+
+int iwch_register_mem(struct iwch_dev *rhp, struct iwch_pd *php,
+ struct iwch_mr *mhp, int shift)
+{
+ u32 stag;
if (cxio_register_phys_mem(&rhp->rdev,
&stag, mhp->attr.pdid,
@@ -53,28 +62,21 @@ int iwch_register_mem(struct iwch_dev *rhp, struct iwch_pd *php,
mhp->attr.zbva,
mhp->attr.va_fbo,
mhp->attr.len,
- shift-12,
- page_list,
- &mhp->attr.pbl_size, &mhp->attr.pbl_addr))
+ shift - 12,
+ mhp->attr.pbl_size, mhp->attr.pbl_addr))
return -ENOMEM;
- mhp->attr.state = 1;
- mhp->attr.stag = stag;
- mmid = stag >> 8;
- mhp->ibmr.rkey = mhp->ibmr.lkey = stag;
- insert_handle(rhp, &rhp->mmidr, mhp, mmid);
- PDBG("%s mmid 0x%x mhp %p\n", __func__, mmid, mhp);
+
+ iwch_finish_mem_reg(mhp, stag);
+
return 0;
}
int iwch_reregister_mem(struct iwch_dev *rhp, struct iwch_pd *php,
struct iwch_mr *mhp,
int shift,
- __be64 *page_list,
int npages)
{
u32 stag;
- u32 mmid;
-
/* We could support this... */
if (npages > mhp->attr.pbl_size)
@@ -87,19 +89,40 @@ int iwch_reregister_mem(struct iwch_dev *rhp, struct iwch_pd *php,
mhp->attr.zbva,
mhp->attr.va_fbo,
mhp->attr.len,
- shift-12,
- page_list,
- &mhp->attr.pbl_size, &mhp->attr.pbl_addr))
+ shift - 12,
+ mhp->attr.pbl_size, mhp->attr.pbl_addr))
return -ENOMEM;
- mhp->attr.state = 1;
- mhp->attr.stag = stag;
- mmid = stag >> 8;
- mhp->ibmr.rkey = mhp->ibmr.lkey = stag;
- insert_handle(rhp, &rhp->mmidr, mhp, mmid);
- PDBG("%s mmid 0x%x mhp %p\n", __func__, mmid, mhp);
+
+ iwch_finish_mem_reg(mhp, stag);
+
+ return 0;
+}
+
+int iwch_alloc_pbl(struct iwch_mr *mhp, int npages)
+{
+ mhp->attr.pbl_addr = cxio_hal_pblpool_alloc(&mhp->rhp->rdev,
+ npages << 3);
+
+ if (!mhp->attr.pbl_addr)
+ return -ENOMEM;
+
+ mhp->attr.pbl_size = npages;
+
return 0;
}
+void iwch_free_pbl(struct iwch_mr *mhp)
+{
+ cxio_hal_pblpool_free(&mhp->rhp->rdev, mhp->attr.pbl_addr,
+ mhp->attr.pbl_size << 3);
+}
+
+int iwch_write_pbl(struct iwch_mr *mhp, __be64 *pages, int npages, int offset)
+{
+ return cxio_write_pbl(&mhp->rhp->rdev, pages,
+ mhp->attr.pbl_addr + (offset << 3), npages);
+}
+
int build_phys_page_list(struct ib_phys_buf *buffer_list,
int num_phys_buf,
u64 *iova_start,
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.c b/drivers/infiniband/hw/cxgb3/iwch_provider.c
index d07d3a377b5..8934178a23e 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.c
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.c
@@ -442,6 +442,7 @@ static int iwch_dereg_mr(struct ib_mr *ib_mr)
mmid = mhp->attr.stag >> 8;
cxio_dereg_mem(&rhp->rdev, mhp->attr.stag, mhp->attr.pbl_size,
mhp->attr.pbl_addr);
+ iwch_free_pbl(mhp);
remove_handle(rhp, &rhp->mmidr, mmid);
if (mhp->kva)
kfree((void *) (unsigned long) mhp->kva);
@@ -475,6 +476,8 @@ static struct ib_mr *iwch_register_phys_mem(struct ib_pd *pd,
if (!mhp)
return ERR_PTR(-ENOMEM);
+ mhp->rhp = rhp;
+
/* First check that we have enough alignment */
if ((*iova_start & ~PAGE_MASK) != (buffer_list[0].addr & ~PAGE_MASK)) {
ret = -EINVAL;
@@ -492,7 +495,17 @@ static struct ib_mr *iwch_register_phys_mem(struct ib_pd *pd,
if (ret)
goto err;
- mhp->rhp = rhp;
+ ret = iwch_alloc_pbl(mhp, npages);
+ if (ret) {
+ kfree(page_list);
+ goto err_pbl;
+ }
+
+ ret = iwch_write_pbl(mhp, page_list, npages, 0);
+ kfree(page_list);
+ if (ret)
+ goto err_pbl;
+
mhp->attr.pdid = php->pdid;
mhp->attr.zbva = 0;
@@ -502,12 +515,15 @@ static struct ib_mr *iwch_register_phys_mem(struct ib_pd *pd,
mhp->attr.len = (u32) total_size;
mhp->attr.pbl_size = npages;
- ret = iwch_register_mem(rhp, php, mhp, shift, page_list);
- kfree(page_list);
- if (ret) {
- goto err;
- }
+ ret = iwch_register_mem(rhp, php, mhp, shift);
+ if (ret)
+ goto err_pbl;
+
return &mhp->ibmr;
+
+err_pbl:
+ iwch_free_pbl(mhp);
+
err:
kfree(mhp);
return ERR_PTR(ret);
@@ -560,7 +576,7 @@ static int iwch_reregister_phys_mem(struct ib_mr *mr,
return ret;
}
- ret = iwch_reregister_mem(rhp, php, &mh, shift, page_list, npages);
+ ret = iwch_reregister_mem(rhp, php, &mh, shift, npages);
kfree(page_list);
if (ret) {
return ret;
@@ -602,6 +618,8 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
if (!mhp)
return ERR_PTR(-ENOMEM);
+ mhp->rhp = rhp;
+
mhp->umem = ib_umem_get(pd->uobject->context, start, length, acc, 0);
if (IS_ERR(mhp->umem)) {
err = PTR_ERR(mhp->umem);
@@ -615,10 +633,14 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
list_for_each_entry(chunk, &mhp->umem->chunk_list, list)
n += chunk->nents;
- pages = kmalloc(n * sizeof(u64), GFP_KERNEL);
+ err = iwch_alloc_pbl(mhp, n);
+ if (err)
+ goto err;
+
+ pages = (__be64 *) __get_free_page(GFP_KERNEL);
if (!pages) {
err = -ENOMEM;
- goto err;
+ goto err_pbl;
}
i = n = 0;
@@ -630,25 +652,38 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
pages[i++] = cpu_to_be64(sg_dma_address(
&chunk->page_list[j]) +
mhp->umem->page_size * k);
+ if (i == PAGE_SIZE / sizeof *pages) {
+ err = iwch_write_pbl(mhp, pages, i, n);
+ if (err)
+ goto pbl_done;
+ n += i;
+ i = 0;
+ }
}
}
- mhp->rhp = rhp;
+ if (i)
+ err = iwch_write_pbl(mhp, pages, i, n);
+
+pbl_done:
+ free_page((unsigned long) pages);
+ if (err)
+ goto err_pbl;
+
mhp->attr.pdid = php->pdid;
mhp->attr.zbva = 0;
mhp->attr.perms = iwch_ib_to_tpt_access(acc);
mhp->attr.va_fbo = virt;
mhp->attr.page_size = shift - 12;
mhp->attr.len = (u32) length;
- mhp->attr.pbl_size = i;
- err = iwch_register_mem(rhp, php, mhp, shift, pages);
- kfree(pages);
+
+ err = iwch_register_mem(rhp, php, mhp, shift);
if (err)
- goto err;
+ goto err_pbl;
if (udata && !t3a_device(rhp)) {
uresp.pbl_addr = (mhp->attr.pbl_addr -
- rhp->rdev.rnic_info.pbl_base) >> 3;
+ rhp->rdev.rnic_info.pbl_base) >> 3;
PDBG("%s user resp pbl_addr 0x%x\n", __func__,
uresp.pbl_addr);
@@ -661,6 +696,9 @@ static struct ib_mr *iwch_reg_user_mr(struct ib_pd *pd, u64 start, u64 length,
return &mhp->ibmr;
+err_pbl:
+ iwch_free_pbl(mhp);
+
err:
ib_umem_release(mhp->umem);
kfree(mhp);
diff --git a/drivers/infiniband/hw/cxgb3/iwch_provider.h b/drivers/infiniband/hw/cxgb3/iwch_provider.h
index db5100d27ca..836163fc542 100644
--- a/drivers/infiniband/hw/cxgb3/iwch_provider.h
+++ b/drivers/infiniband/hw/cxgb3/iwch_provider.h
@@ -340,14 +340,14 @@ int iwch_quiesce_qps(struct iwch_cq *chp);
int iwch_resume_qps(struct iwch_cq *chp);
void stop_read_rep_timer(struct iwch_qp *qhp);
int iwch_register_mem(struct iwch_dev *rhp, struct iwch_pd *php,
- struct iwch_mr *mhp,
- int shift,
- __be64 *page_list);
+ struct iwch_mr *mhp, int shift);
int iwch_reregister_mem(struct iwch_dev *rhp, struct iwch_pd *php,
struct iwch_mr *mhp,
int shift,
- __be64 *page_list,
int npages);
+int iwch_alloc_pbl(struct iwch_mr *mhp, int npages);
+void iwch_free_pbl(struct iwch_mr *mhp);
+int iwch_write_pbl(struct iwch_mr *mhp, __be64 *pages, int npages, int offset);
int build_phys_page_list(struct ib_phys_buf *buffer_list,
int num_phys_buf,
u64 *iova_start,
diff --git a/drivers/infiniband/hw/ehca/ehca_classes.h b/drivers/infiniband/hw/ehca/ehca_classes.h
index 00bab60f6de..1e9e99a1393 100644
--- a/drivers/infiniband/hw/ehca/ehca_classes.h
+++ b/drivers/infiniband/hw/ehca/ehca_classes.h
@@ -192,6 +192,8 @@ struct ehca_qp {
int mtu_shift;
u32 message_count;
u32 packet_count;
+ atomic_t nr_events; /* events seen */
+ wait_queue_head_t wait_completion;
};
#define IS_SRQ(qp) (qp->ext_type == EQPT_SRQ)
diff --git a/drivers/infiniband/hw/ehca/ehca_irq.c b/drivers/infiniband/hw/ehca/ehca_irq.c
index ca5eb0cb628..ce1ab0571be 100644
--- a/drivers/infiniband/hw/ehca/ehca_irq.c
+++ b/drivers/infiniband/hw/ehca/ehca_irq.c
@@ -204,6 +204,8 @@ static void qp_event_callback(struct ehca_shca *shca, u64 eqe,
read_lock(&ehca_qp_idr_lock);
qp = idr_find(&ehca_qp_idr, token);
+ if (qp)
+ atomic_inc(&qp->nr_events);
read_unlock(&ehca_qp_idr_lock);
if (!qp)
@@ -223,6 +225,8 @@ static void qp_event_callback(struct ehca_shca *shca, u64 eqe,
if (fatal && qp->ext_type == EQPT_SRQBASE)
dispatch_qp_event(shca, qp, IB_EVENT_QP_LAST_WQE_REACHED);
+ if (atomic_dec_and_test(&qp->nr_events))
+ wake_up(&qp->wait_completion);
return;
}
diff --git a/drivers/infiniband/hw/ehca/ehca_qp.c b/drivers/infiniband/hw/ehca/ehca_qp.c
index 18fba92fa7a..3f59587338e 100644
--- a/drivers/infiniband/hw/ehca/ehca_qp.c
+++ b/drivers/infiniband/hw/ehca/ehca_qp.c
@@ -566,6 +566,8 @@ static struct ehca_qp *internal_create_qp(
return ERR_PTR(-ENOMEM);
}
+ atomic_set(&my_qp->nr_events, 0);
+ init_waitqueue_head(&my_qp->wait_completion);
spin_lock_init(&my_qp->spinlock_s);
spin_lock_init(&my_qp->spinlock_r);
my_qp->qp_type = qp_type;
@@ -1934,6 +1936,9 @@ static int internal_destroy_qp(struct ib_device *dev, struct ehca_qp *my_qp,
idr_remove(&ehca_qp_idr, my_qp->token);
write_unlock_irqrestore(&ehca_qp_idr_lock, flags);
+ /* now wait until all pending events have completed */
+ wait_event(my_qp->wait_completion, !atomic_read(&my_qp->nr_events));
+
h_ret = hipz_h_destroy_qp(shca->ipz_hca_handle, my_qp);
if (h_ret != H_SUCCESS) {
ehca_err(dev, "hipz_h_destroy_qp() failed h_ret=%li "
diff --git a/drivers/infiniband/hw/ipath/ipath_driver.c b/drivers/infiniband/hw/ipath/ipath_driver.c
index acf30c06a0c..ce7b7c34360 100644
--- a/drivers/infiniband/hw/ipath/ipath_driver.c
+++ b/drivers/infiniband/hw/ipath/ipath_driver.c
@@ -1197,7 +1197,7 @@ void ipath_kreceive(struct ipath_portdata *pd)
}
reloop:
- for (last = 0, i = 1; !last; i++) {
+ for (last = 0, i = 1; !last; i += !last) {
hdr = dd->ipath_f_get_msgheader(dd, rhf_addr);
eflags = ipath_hdrget_err_flags(rhf_addr);
etype = ipath_hdrget_rcv_type(rhf_addr);
@@ -1428,6 +1428,40 @@ static void ipath_update_pio_bufs(struct ipath_devdata *dd)
spin_unlock_irqrestore(&ipath_pioavail_lock, flags);
}
+/*
+ * used to force update of pioavailshadow if we can't get a pio buffer.
+ * Needed primarily due to exitting freeze mode after recovering
+ * from errors. Done lazily, because it's safer (known to not
+ * be writing pio buffers).
+ */
+static void ipath_reset_availshadow(struct ipath_devdata *dd)
+{
+ int i, im;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ipath_pioavail_lock, flags);
+ for (i = 0; i < dd->ipath_pioavregs; i++) {
+ u64 val, oldval;
+ /* deal with 6110 chip bug on high register #s */
+ im = (i > 3 && (dd->ipath_flags & IPATH_SWAP_PIOBUFS)) ?
+ i ^ 1 : i;
+ val = le64_to_cpu(dd->ipath_pioavailregs_dma[im]);
+ /*
+ * busy out the buffers not in the kernel avail list,
+ * without changing the generation bits.
+ */
+ oldval = dd->ipath_pioavailshadow[i];
+ dd->ipath_pioavailshadow[i] = val |
+ ((~dd->ipath_pioavailkernel[i] <<
+ INFINIPATH_SENDPIOAVAIL_BUSY_SHIFT) &
+ 0xaaaaaaaaaaaaaaaaULL); /* All BUSY bits in qword */
+ if (oldval != dd->ipath_pioavailshadow[i])
+ ipath_dbg("shadow[%d] was %Lx, now %lx\n",
+ i, oldval, dd->ipath_pioavailshadow[i]);
+ }
+ spin_unlock_irqrestore(&ipath_pioavail_lock, flags);
+}
+
/**
* ipath_setrcvhdrsize - set the receive header size
* @dd: the infinipath device
@@ -1482,9 +1516,12 @@ static noinline void no_pio_bufs(struct ipath_devdata *dd)
*/
ipath_stats.sps_nopiobufs++;
if (!(++dd->ipath_consec_nopiobuf % 100000)) {
- ipath_dbg("%u pio sends with no bufavail; dmacopy: "
- "%llx %llx %llx %llx; shadow: %lx %lx %lx %lx\n",
+ ipath_force_pio_avail_update(dd); /* at start */
+ ipath_dbg("%u tries no piobufavail ts%lx; dmacopy: "
+ "%llx %llx %llx %llx\n"
+ "ipath shadow: %lx %lx %lx %lx\n",
dd->ipath_consec_nopiobuf,
+ (unsigned long)get_cycles(),
(unsigned long long) le64_to_cpu(dma[0]),
(unsigned long long) le64_to_cpu(dma[1]),
(unsigned long long) le64_to_cpu(dma[2]),
@@ -1496,14 +1533,17 @@ static noinline void no_pio_bufs(struct ipath_devdata *dd)
*/
if ((dd->ipath_piobcnt2k + dd->ipath_piobcnt4k) >
(sizeof(shadow[0]) * 4 * 4))
- ipath_dbg("2nd group: dmacopy: %llx %llx "
- "%llx %llx; shadow: %lx %lx %lx %lx\n",
+ ipath_dbg("2nd group: dmacopy: "
+ "%llx %llx %llx %llx\n"
+ "ipath shadow: %lx %lx %lx %lx\n",
(unsigned long long)le64_to_cpu(dma[4]),
(unsigned long long)le64_to_cpu(dma[5]),
(unsigned long long)le64_to_cpu(dma[6]),
(unsigned long long)le64_to_cpu(dma[7]),
- shadow[4], shadow[5], shadow[6],
- shadow[7]);
+ shadow[4], shadow[5], shadow[6], shadow[7]);
+
+ /* at end, so update likely happened */
+ ipath_reset_availshadow(dd);
}
}
@@ -1652,19 +1692,46 @@ void ipath_chg_pioavailkernel(struct ipath_devdata *dd, unsigned start,
unsigned len, int avail)
{
unsigned long flags;
- unsigned end;
+ unsigned end, cnt = 0, next;
/* There are two bits per send buffer (busy and generation) */
start *= 2;
- len *= 2;
- end = start + len;
+ end = start + len * 2;
- /* Set or clear the generation bits. */
spin_lock_irqsave(&ipath_pioavail_lock, flags);
+ /* Set or clear the busy bit in the shadow. */
while (start < end) {
if (avail) {
- __clear_bit(start + INFINIPATH_SENDPIOAVAIL_BUSY_SHIFT,
- dd->ipath_pioavailshadow);
+ unsigned long dma;
+ int i, im;
+ /*
+ * the BUSY bit will never be set, because we disarm
+ * the user buffers before we hand them back to the
+ * kernel. We do have to make sure the generation
+ * bit is set correctly in shadow, since it could
+ * have changed many times while allocated to user.
+ * We can't use the bitmap functions on the full
+ * dma array because it is always little-endian, so
+ * we have to flip to host-order first.
+ * BITS_PER_LONG is slightly wrong, since it's
+ * always 64 bits per register in chip...
+ * We only work on 64 bit kernels, so that's OK.
+ */
+ /* deal with 6110 chip bug on high register #s */
+ i = start / BITS_PER_LONG;
+ im = (i > 3 && (dd->ipath_flags & IPATH_SWAP_PIOBUFS)) ?
+ i ^ 1 : i;
+ __clear_bit(INFINIPATH_SENDPIOAVAIL_BUSY_SHIFT
+ + start, dd->ipath_pioavailshadow);
+ dma = (unsigned long) le64_to_cpu(
+ dd->ipath_pioavailregs_dma[im]);
+ if (test_bit((INFINIPATH_SENDPIOAVAIL_CHECK_SHIFT
+ + start) % BITS_PER_LONG, &dma))
+ __set_bit(INFINIPATH_SENDPIOAVAIL_CHECK_SHIFT
+ + start, dd->ipath_pioavailshadow);
+ else
+ __clear_bit(INFINIPATH_SENDPIOAVAIL_CHECK_SHIFT
+ + start, dd->ipath_pioavailshadow);
__set_bit(start, dd->ipath_pioavailkernel);
} else {
__set_bit(start + INFINIPATH_SENDPIOAVAIL_BUSY_SHIFT,
@@ -1673,7 +1740,44 @@ void ipath_chg_pioavailkernel(struct ipath_devdata *dd, unsigned start,
}
start += 2;
}
+
+ if (dd->ipath_pioupd_thresh) {
+ end = 2 * (dd->ipath_piobcnt2k + dd->ipath_piobcnt4k);
+ next = find_first_bit(dd->ipath_pioavailkernel, end);
+ while (next < end) {
+ cnt++;
+ next = find_next_bit(dd->ipath_pioavailkernel, end,
+ next + 1);
+ }
+ }
spin_unlock_irqrestore(&ipath_pioavail_lock, flags);
+
+ /*
+ * When moving buffers from kernel to user, if number assigned to
+ * the user is less than the pio update threshold, and threshold
+ * is supported (cnt was computed > 0), drop the update threshold
+ * so we update at least once per allocated number of buffers.
+ * In any case, if the kernel buffers are less than the threshold,
+ * drop the threshold. We don't bother increasing it, having once
+ * decreased it, since it would typically just cycle back and forth.
+ * If we don't decrease below buffers in use, we can wait a long
+ * time for an update, until some other context uses PIO buffers.
+ */
+ if (!avail && len < cnt)
+ cnt = len;
+ if (cnt < dd->ipath_pioupd_thresh) {
+ dd->ipath_pioupd_thresh = cnt;
+ ipath_dbg("Decreased pio update threshold to %u\n",
+ dd->ipath_pioupd_thresh);
+ spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
+ dd->ipath_sendctrl &= ~(INFINIPATH_S_UPDTHRESH_MASK
+ << INFINIPATH_S_UPDTHRESH_SHIFT);
+ dd->ipath_sendctrl |= dd->ipath_pioupd_thresh
+ << INFINIPATH_S_UPDTHRESH_SHIFT;
+ ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
+ dd->ipath_sendctrl);
+ spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
+ }
}
/**
@@ -1794,8 +1898,8 @@ void ipath_cancel_sends(struct ipath_devdata *dd, int restore_sendctrl)
spin_lock_irqsave(&dd->ipath_sdma_lock, flags);
skip_cancel =
- !test_bit(IPATH_SDMA_DISABLED, statp) &&
- test_and_set_bit(IPATH_SDMA_ABORTING, statp);
+ test_and_set_bit(IPATH_SDMA_ABORTING, statp)
+ && !test_bit(IPATH_SDMA_DISABLED, statp);
spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
if (skip_cancel)
goto bail;
@@ -1826,6 +1930,9 @@ void ipath_cancel_sends(struct ipath_devdata *dd, int restore_sendctrl)
ipath_disarm_piobufs(dd, 0,
dd->ipath_piobcnt2k + dd->ipath_piobcnt4k);
+ if (dd->ipath_flags & IPATH_HAS_SEND_DMA)
+ set_bit(IPATH_SDMA_DISARMED, &dd->ipath_sdma_status);
+
if (restore_sendctrl) {
/* else done by caller later if needed */
spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
@@ -1845,7 +1952,6 @@ void ipath_cancel_sends(struct ipath_devdata *dd, int restore_sendctrl)
/* only wait so long for intr */
dd->ipath_sdma_abort_intr_timeout = jiffies + HZ;
dd->ipath_sdma_reset_wait = 200;
- __set_bit(IPATH_SDMA_DISARMED, &dd->ipath_sdma_status);
if (!test_bit(IPATH_SDMA_SHUTDOWN, &dd->ipath_sdma_status))
tasklet_hi_schedule(&dd->ipath_sdma_abort_task);
spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
diff --git a/drivers/infiniband/hw/ipath/ipath_file_ops.c b/drivers/infiniband/hw/ipath/ipath_file_ops.c
index 8b1752202e7..3295177c937 100644
--- a/drivers/infiniband/hw/ipath/ipath_file_ops.c
+++ b/drivers/infiniband/hw/ipath/ipath_file_ops.c
@@ -173,47 +173,25 @@ static int ipath_get_base_info(struct file *fp,
(void *) dd->ipath_statusp -
(void *) dd->ipath_pioavailregs_dma;
if (!shared) {
- kinfo->spi_piocnt = dd->ipath_pbufsport;
+ kinfo->spi_piocnt = pd->port_piocnt;
kinfo->spi_piobufbase = (u64) pd->port_piobufs;
kinfo->__spi_uregbase = (u64) dd->ipath_uregbase +
dd->ipath_ureg_align * pd->port_port;
} else if (master) {
- kinfo->spi_piocnt = (dd->ipath_pbufsport / subport_cnt) +
- (dd->ipath_pbufsport % subport_cnt);
+ kinfo->spi_piocnt = (pd->port_piocnt / subport_cnt) +
+ (pd->port_piocnt % subport_cnt);
/* Master's PIO buffers are after all the slave's */
kinfo->spi_piobufbase = (u64) pd->port_piobufs +
dd->ipath_palign *
- (dd->ipath_pbufsport - kinfo->spi_piocnt);
+ (pd->port_piocnt - kinfo->spi_piocnt);
} else {
unsigned slave = subport_fp(fp) - 1;
- kinfo->spi_piocnt = dd->ipath_pbufsport / subport_cnt;
+ kinfo->spi_piocnt = pd->port_piocnt / subport_cnt;
kinfo->spi_piobufbase = (u64) pd->port_piobufs +
dd->ipath_palign * kinfo->spi_piocnt * slave;
}
- /*
- * Set the PIO avail update threshold to no larger
- * than the number of buffers per process. Note that
- * we decrease it here, but won't ever increase it.
- */
- if (dd->ipath_pioupd_thresh &&
- kinfo->spi_piocnt < dd->ipath_pioupd_thresh) {
- unsigned long flags;
-
- dd->ipath_pioupd_thresh = kinfo->spi_piocnt;
- ipath_dbg("Decreased pio update threshold to %u\n",
- dd->ipath_pioupd_thresh);
- spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
- dd->ipath_sendctrl &= ~(INFINIPATH_S_UPDTHRESH_MASK
- << INFINIPATH_S_UPDTHRESH_SHIFT);
- dd->ipath_sendctrl |= dd->ipath_pioupd_thresh
- << INFINIPATH_S_UPDTHRESH_SHIFT;
- ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl,
- dd->ipath_sendctrl);
- spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
- }
-
if (shared) {
kinfo->spi_port_uregbase = (u64) dd->ipath_uregbase +
dd->ipath_ureg_align * pd->port_port;
@@ -1309,19 +1287,19 @@ static int ipath_mmap(struct file *fp, struct vm_area_struct *vma)
ureg = dd->ipath_uregbase + dd->ipath_ureg_align * pd->port_port;
if (!pd->port_subport_cnt) {
/* port is not shared */
- piocnt = dd->ipath_pbufsport;
+ piocnt = pd->port_piocnt;
piobufs = pd->port_piobufs;
} else if (!subport_fp(fp)) {
/* caller is the master */
- piocnt = (dd->ipath_pbufsport / pd->port_subport_cnt) +
- (dd->ipath_pbufsport % pd->port_subport_cnt);
+ piocnt = (pd->port_piocnt / pd->port_subport_cnt) +
+ (pd->port_piocnt % pd->port_subport_cnt);
piobufs = pd->port_piobufs +
- dd->ipath_palign * (dd->ipath_pbufsport - piocnt);
+ dd->ipath_palign * (pd->port_piocnt - piocnt);
} else {
unsigned slave = subport_fp(fp) - 1;
/* caller is a slave */
- piocnt = dd->ipath_pbufsport / pd->port_subport_cnt;
+ piocnt = pd->port_piocnt / pd->port_subport_cnt;
piobufs = pd->port_piobufs + dd->ipath_palign * piocnt * slave;
}
@@ -1633,9 +1611,6 @@ static int try_alloc_port(struct ipath_devdata *dd, int port,
port_fp(fp) = pd;
pd->port_pid = current->pid;
strncpy(pd->port_comm, current->comm, sizeof(pd->port_comm));
- ipath_chg_pioavailkernel(dd,
- dd->ipath_pbufsport * (pd->port_port - 1),
- dd->ipath_pbufsport, 0);
ipath_stats.sps_ports++;
ret = 0;
} else
@@ -1938,11 +1913,25 @@ static int ipath_do_user_init(struct file *fp,
/* for now we do nothing with rcvhdrcnt: uinfo->spu_rcvhdrcnt */
+ /* some ports may get extra buffers, calculate that here */
+ if (pd->port_port <= dd->ipath_ports_extrabuf)
+ pd->port_piocnt = dd->ipath_pbufsport + 1;
+ else
+ pd->port_piocnt = dd->ipath_pbufsport;
+
/* for right now, kernel piobufs are at end, so port 1 is at 0 */
+ if (pd->port_port <= dd->ipath_ports_extrabuf)
+ pd->port_pio_base = (dd->ipath_pbufsport + 1)
+ * (pd->port_port - 1);
+ else
+ pd->port_pio_base = dd->ipath_ports_extrabuf +
+ dd->ipath_pbufsport * (pd->port_port - 1);
pd->port_piobufs = dd->ipath_piobufbase +
- dd->ipath_pbufsport * (pd->port_port - 1) * dd->ipath_palign;
- ipath_cdbg(VERBOSE, "Set base of piobufs for port %u to 0x%x\n",
- pd->port_port, pd->port_piobufs);
+ pd->port_pio_base * dd->ipath_palign;
+ ipath_cdbg(VERBOSE, "piobuf base for port %u is 0x%x, piocnt %u,"
+ " first pio %u\n", pd->port_port, pd->port_piobufs,
+ pd->port_piocnt, pd->port_pio_base);
+ ipath_chg_pioavailkernel(dd, pd->port_pio_base, pd->port_piocnt, 0);
/*
* Now allocate the rcvhdr Q and eager TIDs; skip the TID
@@ -2107,7 +2096,6 @@ static int ipath_close(struct inode *in, struct file *fp)
}
if (dd->ipath_kregbase) {
- int i;
/* atomically clear receive enable port and intr avail. */
clear_bit(dd->ipath_r_portenable_shift + port,
&dd->ipath_rcvctrl);
@@ -2136,9 +2124,9 @@ static int ipath_close(struct inode *in, struct file *fp)
ipath_write_kreg_port(dd, dd->ipath_kregs->kr_rcvhdraddr,
pd->port_port, dd->ipath_dummy_hdrq_phys);
- i = dd->ipath_pbufsport * (port - 1);
- ipath_disarm_piobufs(dd, i, dd->ipath_pbufsport);
- ipath_chg_pioavailkernel(dd, i, dd->ipath_pbufsport, 1);
+ ipath_disarm_piobufs(dd, pd->port_pio_base, pd->port_piocnt);
+ ipath_chg_pioavailkernel(dd, pd->port_pio_base,
+ pd->port_piocnt, 1);
dd->ipath_f_clear_tids(dd, pd->port_port);
diff --git a/drivers/infiniband/hw/ipath/ipath_iba7220.c b/drivers/infiniband/hw/ipath/ipath_iba7220.c
index e3ec0d1bdf5..8eee7830f04 100644
--- a/drivers/infiniband/hw/ipath/ipath_iba7220.c
+++ b/drivers/infiniband/hw/ipath/ipath_iba7220.c
@@ -595,7 +595,7 @@ static void ipath_7220_txe_recover(struct ipath_devdata *dd)
dev_info(&dd->pcidev->dev,
"Recovering from TXE PIO parity error\n");
- ipath_disarm_senderrbufs(dd, 1);
+ ipath_disarm_senderrbufs(dd);
}
@@ -675,10 +675,8 @@ static void ipath_7220_handle_hwerrors(struct ipath_devdata *dd, char *msg,
ctrl = ipath_read_kreg32(dd, dd->ipath_kregs->kr_control);
if ((ctrl & INFINIPATH_C_FREEZEMODE) && !ipath_diag_inuse) {
/*
- * Parity errors in send memory are recoverable,
- * just cancel the send (if indicated in * sendbuffererror),
- * count the occurrence, unfreeze (if no other handled
- * hardware error bits are set), and continue.
+ * Parity errors in send memory are recoverable by h/w
+ * just do housekeeping, exit freeze mode and continue.
*/
if (hwerrs & ((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF |
INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC)
@@ -687,13 +685,6 @@ static void ipath_7220_handle_hwerrors(struct ipath_devdata *dd, char *msg,
hwerrs &= ~((INFINIPATH_HWE_TXEMEMPARITYERR_PIOBUF |
INFINIPATH_HWE_TXEMEMPARITYERR_PIOPBC)
<< INFINIPATH_HWE_TXEMEMPARITYERR_SHIFT);
- if (!hwerrs) {
- /* else leave in freeze mode */
- ipath_write_kreg(dd,
- dd->ipath_kregs->kr_control,
- dd->ipath_control);
- goto bail;
- }
}
if (hwerrs) {
/*
@@ -723,8 +714,8 @@ static void ipath_7220_handle_hwerrors(struct ipath_devdata *dd, char *msg,
*dd->ipath_statusp |= IPATH_STATUS_HWERROR;
dd->ipath_flags &= ~IPATH_INITTED;
} else {
- ipath_dbg("Clearing freezemode on ignored hardware "
- "error\n");
+ ipath_dbg("Clearing freezemode on ignored or "
+ "recovered hardware error\n");
ipath_clear_freeze(dd);
}
}
@@ -870,8 +861,9 @@ static int ipath_7220_boardname(struct ipath_devdata *dd, char *name,
"revision %u.%u!\n",
dd->ipath_majrev, dd->ipath_minrev);
ret = 1;
- } else if (dd->ipath_minrev == 1) {
- /* Rev1 chips are prototype. Complain, but allow use */
+ } else if (dd->ipath_minrev == 1 &&
+ !(dd->ipath_flags & IPATH_INITTED)) {
+ /* Rev1 chips are prototype. Complain at init, but allow use */
ipath_dev_err(dd, "Unsupported hardware "
"revision %u.%u, Contact support@qlogic.com\n",
dd->ipath_majrev, dd->ipath_minrev);
@@ -1966,7 +1958,7 @@ static void ipath_7220_config_ports(struct ipath_devdata *dd, ushort cfgports)
dd->ipath_rcvctrl);
dd->ipath_p0_rcvegrcnt = 2048; /* always */
if (dd->ipath_flags & IPATH_HAS_SEND_DMA)
- dd->ipath_pioreserved = 1; /* reserve a buffer */
+ dd->ipath_pioreserved = 3; /* kpiobufs used for PIO */
}
diff --git a/drivers/infiniband/hw/ipath/ipath_init_chip.c b/drivers/infiniband/hw/ipath/ipath_init_chip.c
index 27dd8947666..3e5baa43fc8 100644
--- a/drivers/infiniband/hw/ipath/ipath_init_chip.c
+++ b/drivers/infiniband/hw/ipath/ipath_init_chip.c
@@ -41,7 +41,7 @@
/*
* min buffers we want to have per port, after driver
*/
-#define IPATH_MIN_USER_PORT_BUFCNT 8
+#define IPATH_MIN_USER_PORT_BUFCNT 7
/*
* Number of ports we are configured to use (to allow for more pio
@@ -54,13 +54,9 @@ MODULE_PARM_DESC(cfgports, "Set max number of ports to use");
/*
* Number of buffers reserved for driver (verbs and layered drivers.)
- * Reserved at end of buffer list. Initialized based on
- * number of PIO buffers if not set via module interface.
+ * Initialized based on number of PIO buffers if not set via module interface.
* The problem with this is that it's global, but we'll use different
- * numbers for different chip types. So the default value is not
- * very useful. I've redefined it for the 1.3 release so that it's
- * zero unless set by the user to something else, in which case we
- * try to respect it.
+ * numbers for different chip types.
*/
static ushort ipath_kpiobufs;
@@ -546,9 +542,12 @@ static void enable_chip(struct ipath_devdata *dd, int reinit)
pioavail = dd->ipath_pioavailregs_dma[i ^ 1];
else
pioavail = dd->ipath_pioavailregs_dma[i];
- dd->ipath_pioavailshadow[i] = le64_to_cpu(pioavail) |
- (~dd->ipath_pioavailkernel[i] <<
- INFINIPATH_SENDPIOAVAIL_BUSY_SHIFT);
+ /*
+ * don't need to worry about ipath_pioavailkernel here
+ * because we will call ipath_chg_pioavailkernel() later
+ * in initialization, to busy out buffers as needed
+ */
+ dd->ipath_pioavailshadow[i] = le64_to_cpu(pioavail);
}
/* can get counters, stats, etc. */
dd->ipath_flags |= IPATH_PRESENT;
@@ -708,12 +707,11 @@ static void verify_interrupt(unsigned long opaque)
int ipath_init_chip(struct ipath_devdata *dd, int reinit)
{
int ret = 0;
- u32 val32, kpiobufs;
+ u32 kpiobufs, defkbufs;
u32 piobufs, uports;
u64 val;
struct ipath_portdata *pd;
gfp_t gfp_flags = GFP_USER | __GFP_COMP;
- unsigned long flags;
ret = init_housekeeping(dd, reinit);
if (ret)
@@ -753,56 +751,46 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
dd->ipath_pioavregs = ALIGN(piobufs, sizeof(u64) * BITS_PER_BYTE / 2)
/ (sizeof(u64) * BITS_PER_BYTE / 2);
uports = dd->ipath_cfgports ? dd->ipath_cfgports - 1 : 0;
- if (ipath_kpiobufs == 0) {
- /* not set by user (this is default) */
- if (piobufs > 144)
- kpiobufs = 32;
- else
- kpiobufs = 16;
- }
+ if (piobufs > 144)
+ defkbufs = 32 + dd->ipath_pioreserved;
else
- kpiobufs = ipath_kpiobufs;
+ defkbufs = 16 + dd->ipath_pioreserved;
- if (kpiobufs + (uports * IPATH_MIN_USER_PORT_BUFCNT) > piobufs) {
+ if (ipath_kpiobufs && (ipath_kpiobufs +
+ (uports * IPATH_MIN_USER_PORT_BUFCNT)) > piobufs) {
int i = (int) piobufs -
(int) (uports * IPATH_MIN_USER_PORT_BUFCNT);
if (i < 1)
i = 1;
dev_info(&dd->pcidev->dev, "Allocating %d PIO bufs of "
"%d for kernel leaves too few for %d user ports "
- "(%d each); using %u\n", kpiobufs,
+ "(%d each); using %u\n", ipath_kpiobufs,
piobufs, uports, IPATH_MIN_USER_PORT_BUFCNT, i);
/*
* shouldn't change ipath_kpiobufs, because could be
* different for different devices...
*/
kpiobufs = i;
- }
+ } else if (ipath_kpiobufs)
+ kpiobufs = ipath_kpiobufs;
+ else
+ kpiobufs = defkbufs;
dd->ipath_lastport_piobuf = piobufs - kpiobufs;
dd->ipath_pbufsport =
uports ? dd->ipath_lastport_piobuf / uports : 0;
- val32 = dd->ipath_lastport_piobuf - (dd->ipath_pbufsport * uports);
- if (val32 > 0) {
- ipath_dbg("allocating %u pbufs/port leaves %u unused, "
- "add to kernel\n", dd->ipath_pbufsport, val32);
- dd->ipath_lastport_piobuf -= val32;
- kpiobufs += val32;
- ipath_dbg("%u pbufs/port leaves %u unused, add to kernel\n",
- dd->ipath_pbufsport, val32);
- }
+ /* if not an even divisor, some user ports get extra buffers */
+ dd->ipath_ports_extrabuf = dd->ipath_lastport_piobuf -
+ (dd->ipath_pbufsport * uports);
+ if (dd->ipath_ports_extrabuf)
+ ipath_dbg("%u pbufs/port leaves some unused, add 1 buffer to "
+ "ports <= %u\n", dd->ipath_pbufsport,
+ dd->ipath_ports_extrabuf);
dd->ipath_lastpioindex = 0;
dd->ipath_lastpioindexl = dd->ipath_piobcnt2k;
- ipath_chg_pioavailkernel(dd, 0, piobufs, 1);
+ /* ipath_pioavailshadow initialized earlier */
ipath_cdbg(VERBOSE, "%d PIO bufs for kernel out of %d total %u "
"each for %u user ports\n", kpiobufs,
piobufs, dd->ipath_pbufsport, uports);
- if (dd->ipath_pioupd_thresh) {
- if (dd->ipath_pbufsport < dd->ipath_pioupd_thresh)
- dd->ipath_pioupd_thresh = dd->ipath_pbufsport;
- if (kpiobufs < dd->ipath_pioupd_thresh)
- dd->ipath_pioupd_thresh = kpiobufs;
- }
-
ret = dd->ipath_f_early_init(dd);
if (ret) {
ipath_dev_err(dd, "Early initialization failure\n");
@@ -810,13 +798,6 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
}
/*
- * Cancel any possible active sends from early driver load.
- * Follows early_init because some chips have to initialize
- * PIO buffers in early_init to avoid false parity errors.
- */
- ipath_cancel_sends(dd, 0);
-
- /*
* Early_init sets rcvhdrentsize and rcvhdrsize, so this must be
* done after early_init.
*/
@@ -836,6 +817,7 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
ipath_write_kreg(dd, dd->ipath_kregs->kr_sendpioavailaddr,
dd->ipath_pioavailregs_phys);
+
/*
* this is to detect s/w errors, which the h/w works around by
* ignoring the low 6 bits of address, if it wasn't aligned.
@@ -862,12 +844,6 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
~0ULL&~INFINIPATH_HWE_MEMBISTFAILED);
ipath_write_kreg(dd, dd->ipath_kregs->kr_control, 0ULL);
- spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
- dd->ipath_sendctrl = INFINIPATH_S_PIOENABLE;
- ipath_write_kreg(dd, dd->ipath_kregs->kr_sendctrl, dd->ipath_sendctrl);
- ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
- spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
-
/*
* before error clears, since we expect serdes pll errors during
* this, the first time after reset
@@ -940,6 +916,19 @@ int ipath_init_chip(struct ipath_devdata *dd, int reinit)
else
enable_chip(dd, reinit);
+ /* after enable_chip, so pioavailshadow setup */
+ ipath_chg_pioavailkernel(dd, 0, piobufs, 1);
+
+ /*
+ * Cancel any possible active sends from early driver load.
+ * Follows early_init because some chips have to initialize
+ * PIO buffers in early_init to avoid false parity errors.
+ * After enable and ipath_chg_pioavailkernel so we can safely
+ * enable pioavail updates and PIOENABLE; packets are now
+ * ready to go out.
+ */
+ ipath_cancel_sends(dd, 1);
+
if (!reinit) {
/*
* Used when we close a port, for DMA already in flight
diff --git a/drivers/infiniband/hw/ipath/ipath_intr.c b/drivers/infiniband/hw/ipath/ipath_intr.c
index 1b58f4737c7..26900b3b7a4 100644
--- a/drivers/infiniband/hw/ipath/ipath_intr.c
+++ b/drivers/infiniband/hw/ipath/ipath_intr.c
@@ -38,42 +38,12 @@
#include "ipath_verbs.h"
#include "ipath_common.h"
-/*
- * clear (write) a pio buffer, to clear a parity error. This routine
- * should only be called when in freeze mode, and the buffer should be
- * canceled afterwards.
- */
-static void ipath_clrpiobuf(struct ipath_devdata *dd, u32 pnum)
-{
- u32 __iomem *pbuf;
- u32 dwcnt; /* dword count to write */
- if (pnum < dd->ipath_piobcnt2k) {
- pbuf = (u32 __iomem *) (dd->ipath_pio2kbase + pnum *
- dd->ipath_palign);
- dwcnt = dd->ipath_piosize2k >> 2;
- }
- else {
- pbuf = (u32 __iomem *) (dd->ipath_pio4kbase +
- (pnum - dd->ipath_piobcnt2k) * dd->ipath_4kalign);
- dwcnt = dd->ipath_piosize4k >> 2;
- }
- dev_info(&dd->pcidev->dev,
- "Rewrite PIO buffer %u, to recover from parity error\n",
- pnum);
-
- /* no flush required, since already in freeze */
- writel(dwcnt + 1, pbuf);
- while (--dwcnt)
- writel(0, pbuf++);
-}
/*
* Called when we might have an error that is specific to a particular
* PIO buffer, and may need to cancel that buffer, so it can be re-used.
- * If rewrite is true, and bits are set in the sendbufferror registers,
- * we'll write to the buffer, for error recovery on parity errors.
*/
-void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite)
+void ipath_disarm_senderrbufs(struct ipath_devdata *dd)
{
u32 piobcnt;
unsigned long sbuf[4];
@@ -109,11 +79,8 @@ void ipath_disarm_senderrbufs(struct ipath_devdata *dd, int rewrite)
}
for (i = 0; i < piobcnt; i++)
- if (test_bit(i, sbuf)) {
- if (rewrite)
- ipath_clrpiobuf(dd, i);
+ if (test_bit(i, sbuf))
ipath_disarm_piobufs(dd, i, 1);
- }
/* ignore armlaunch errs for a bit */
dd->ipath_lastcancel = jiffies+3;
}
@@ -164,7 +131,7 @@ static u64 handle_e_sum_errs(struct ipath_devdata *dd, ipath_err_t errs)
{
u64 ignore_this_time = 0;
- ipath_disarm_senderrbufs(dd, 0);
+ ipath_disarm_senderrbufs(dd);
if ((errs & E_SUM_LINK_PKTERRS) &&
!(dd->ipath_flags & IPATH_LINKACTIVE)) {
/*
@@ -909,8 +876,8 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
* processes (causing armlaunch), send errors due to going into freeze mode,
* etc., and try to avoid causing extra interrupts while doing so.
* Forcibly update the in-memory pioavail register copies after cleanup
- * because the chip won't do it for anything changing while in freeze mode
- * (we don't want to wait for the next pio buffer state change).
+ * because the chip won't do it while in freeze mode (the register values
+ * themselves are kept correct).
* Make sure that we don't lose any important interrupts by using the chip
* feature that says that writing 0 to a bit in *clear that is set in
* *status will cause an interrupt to be generated again (if allowed by
@@ -918,44 +885,23 @@ static int handle_errors(struct ipath_devdata *dd, ipath_err_t errs)
*/
void ipath_clear_freeze(struct ipath_devdata *dd)
{
- int i, im;
- u64 val;
-
/* disable error interrupts, to avoid confusion */
ipath_write_kreg(dd, dd->ipath_kregs->kr_errormask, 0ULL);
/* also disable interrupts; errormask is sometimes overwriten */
ipath_write_kreg(dd, dd->ipath_kregs->kr_intmask, 0ULL);
- /*
- * clear all sends, because they have may been
- * completed by usercode while in freeze mode, and
- * therefore would not be sent, and eventually
- * might cause the process to run out of bufs
- */
- ipath_cancel_sends(dd, 0);
+ ipath_cancel_sends(dd, 1);
+
+ /* clear the freeze, and be sure chip saw it */
ipath_write_kreg(dd, dd->ipath_kregs->kr_control,
dd->ipath_control);
+ ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
- /* ensure pio avail updates continue */
+ /* force in-memory update now we are out of freeze */
ipath_force_pio_avail_update(dd);
/*
- * We just enabled pioavailupdate, so dma copy is almost certainly
- * not yet right, so read the registers directly. Similar to init
- */
- for (i = 0; i < dd->ipath_pioavregs; i++) {
- /* deal with 6110 chip bug */
- im = (i > 3 && (dd->ipath_flags & IPATH_SWAP_PIOBUFS)) ?
- i ^ 1 : i;
- val = ipath_read_kreg64(dd, (0x1000 / sizeof(u64)) + im);
- dd->ipath_pioavailregs_dma[i] = cpu_to_le64(val);
- dd->ipath_pioavailshadow[i] = val |
- (~dd->ipath_pioavailkernel[i] <<
- INFINIPATH_SENDPIOAVAIL_BUSY_SHIFT);
- }
-
- /*
* force new interrupt if any hwerr, error or interrupt bits are
* still set, and clear "safe" send packet errors related to freeze
* and cancelling sends. Re-enable error interrupts before possible
@@ -1312,10 +1258,8 @@ irqreturn_t ipath_intr(int irq, void *data)
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
- if (!(dd->ipath_flags & IPATH_HAS_SEND_DMA))
- handle_layer_pioavail(dd);
- else
- ipath_dbg("unexpected BUFAVAIL intr\n");
+ /* always process; sdma verbs uses PIO for acks and VL15 */
+ handle_layer_pioavail(dd);
}
ret = IRQ_HANDLED;
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h
index 202337ae90d..02b24a34059 100644
--- a/drivers/infiniband/hw/ipath/ipath_kernel.h
+++ b/drivers/infiniband/hw/ipath/ipath_kernel.h
@@ -117,6 +117,10 @@ struct ipath_portdata {
u16 port_subport_cnt;
/* non-zero if port is being shared. */
u16 port_subport_id;
+ /* number of pio bufs for this port (all procs, if shared) */
+ u32 port_piocnt;
+ /* first pio buffer for this port */
+ u32 port_pio_base;
/* chip offset of PIO buffers for this port */
u32 port_piobufs;
/* how many alloc_pages() chunks in port_rcvegrbuf_pages */
@@ -384,6 +388,8 @@ struct ipath_devdata {
u32 ipath_lastrpkts;
/* pio bufs allocated per port */
u32 ipath_pbufsport;
+ /* if remainder on bufs/port, ports < extrabuf get 1 extra */
+ u32 ipath_ports_extrabuf;
u32 ipath_pioupd_thresh; /* update threshold, some chips */
/*
* number of ports configured as max; zero is set to number chip
@@ -1011,7 +1017,7 @@ void ipath_get_eeprom_info(struct ipath_devdata *);
int ipath_update_eeprom_log(struct ipath_devdata *dd);
void ipath_inc_eeprom_err(struct ipath_devdata *dd, u32 eidx, u32 incr);
u64 ipath_snap_cntr(struct ipath_devdata *, ipath_creg);
-void ipath_disarm_senderrbufs(struct ipath_devdata *, int);
+void ipath_disarm_senderrbufs(struct ipath_devdata *);
void ipath_force_pio_avail_update(struct ipath_devdata *);
void signal_ib_event(struct ipath_devdata *dd, enum ib_event_type ev);
diff --git a/drivers/infiniband/hw/ipath/ipath_rc.c b/drivers/infiniband/hw/ipath/ipath_rc.c
index c405dfba553..08b11b56761 100644
--- a/drivers/infiniband/hw/ipath/ipath_rc.c
+++ b/drivers/infiniband/hw/ipath/ipath_rc.c
@@ -1746,7 +1746,11 @@ void ipath_rc_rcv(struct ipath_ibdev *dev, struct ipath_ib_header *hdr,
qp->r_wrid_valid = 0;
wc.wr_id = qp->r_wr_id;
wc.status = IB_WC_SUCCESS;
- wc.opcode = IB_WC_RECV;
+ if (opcode == OP(RDMA_WRITE_LAST_WITH_IMMEDIATE) ||
+ opcode == OP(RDMA_WRITE_ONLY_WITH_IMMEDIATE))
+ wc.opcode = IB_WC_RECV_RDMA_WITH_IMM;
+ else
+ wc.opcode = IB_WC_RECV;
wc.vendor_err = 0;
wc.qp = &qp->ibqp;
wc.src_qp = qp->remote_qpn;
diff --git a/drivers/infiniband/hw/ipath/ipath_ruc.c b/drivers/infiniband/hw/ipath/ipath_ruc.c
index 8ac5c1d82cc..9e3fe61cbd0 100644
--- a/drivers/infiniband/hw/ipath/ipath_ruc.c
+++ b/drivers/infiniband/hw/ipath/ipath_ruc.c
@@ -481,9 +481,10 @@ done:
wake_up(&qp->wait);
}
-static void want_buffer(struct ipath_devdata *dd)
+static void want_buffer(struct ipath_devdata *dd, struct ipath_qp *qp)
{
- if (!(dd->ipath_flags & IPATH_HAS_SEND_DMA)) {
+ if (!(dd->ipath_flags & IPATH_HAS_SEND_DMA) ||
+ qp->ibqp.qp_type == IB_QPT_SMI) {
unsigned long flags;
spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
@@ -519,7 +520,7 @@ static void ipath_no_bufs_available(struct ipath_qp *qp,
spin_lock_irqsave(&dev->pending_lock, flags);
list_add_tail(&qp->piowait, &dev->piowait);
spin_unlock_irqrestore(&dev->pending_lock, flags);
- want_buffer(dev->dd);
+ want_buffer(dev->dd, qp);
dev->n_piowait++;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_sdma.c b/drivers/infiniband/hw/ipath/ipath_sdma.c
index 1974df7a9f7..3697449c1ba 100644
--- a/drivers/infiniband/hw/ipath/ipath_sdma.c
+++ b/drivers/infiniband/hw/ipath/ipath_sdma.c
@@ -308,13 +308,15 @@ static void sdma_abort_task(unsigned long opaque)
spin_unlock_irqrestore(&dd->ipath_sdma_lock, flags);
/*
- * Don't restart sdma here. Wait until link is up to ACTIVE.
- * VL15 MADs used to bring the link up use PIO, and multiple
- * link transitions otherwise cause the sdma engine to be
+ * Don't restart sdma here (with the exception
+ * below). Wait until link is up to ACTIVE. VL15 MADs
+ * used to bring the link up use PIO, and multiple link
+ * transitions otherwise cause the sdma engine to be
* stopped and started multiple times.
- * The disable is done here, including the shadow, so the
- * state is kept consistent.
- * See ipath_restart_sdma() for the actual starting of sdma.
+ * The disable is done here, including the shadow,
+ * so the state is kept consistent.
+ * See ipath_restart_sdma() for the actual starting
+ * of sdma.
*/
spin_lock_irqsave(&dd->ipath_sendctrl_lock, flags);
dd->ipath_sendctrl &= ~INFINIPATH_S_SDMAENABLE;
@@ -326,6 +328,13 @@ static void sdma_abort_task(unsigned long opaque)
/* make sure I see next message */
dd->ipath_sdma_abort_jiffies = 0;
+ /*
+ * Not everything that takes SDMA offline is a link
+ * status change. If the link was up, restart SDMA.
+ */
+ if (dd->ipath_flags & IPATH_LINKACTIVE)
+ ipath_restart_sdma(dd);
+
goto done;
}
@@ -427,7 +436,12 @@ int setup_sdma(struct ipath_devdata *dd)
goto done;
}
- dd->ipath_sdma_status = 0;
+ /*
+ * Set initial status as if we had been up, then gone down.
+ * This lets initial start on transition to ACTIVE be the
+ * same as restart after link flap.
+ */
+ dd->ipath_sdma_status = IPATH_SDMA_ABORT_ABORTED;
dd->ipath_sdma_abort_jiffies = 0;
dd->ipath_sdma_generation = 0;
dd->ipath_sdma_descq_tail = 0;
@@ -449,16 +463,19 @@ int setup_sdma(struct ipath_devdata *dd)
ipath_write_kreg(dd, dd->ipath_kregs->kr_senddmaheadaddr,
dd->ipath_sdma_head_phys);
- /* Reserve all the former "kernel" piobufs */
- n = dd->ipath_piobcnt2k + dd->ipath_piobcnt4k - dd->ipath_pioreserved;
- for (i = dd->ipath_lastport_piobuf; i < n; ++i) {
+ /*
+ * Reserve all the former "kernel" piobufs, using high number range
+ * so we get as many 4K buffers as possible
+ */
+ n = dd->ipath_piobcnt2k + dd->ipath_piobcnt4k;
+ i = dd->ipath_lastport_piobuf + dd->ipath_pioreserved;
+ ipath_chg_pioavailkernel(dd, i, n - i , 0);
+ for (; i < n; ++i) {
unsigned word = i / 64;
unsigned bit = i & 63;
BUG_ON(word >= 3);
senddmabufmask[word] |= 1ULL << bit;
}
- ipath_chg_pioavailkernel(dd, dd->ipath_lastport_piobuf,
- n - dd->ipath_lastport_piobuf, 0);
ipath_write_kreg(dd, dd->ipath_kregs->kr_senddmabufmask0,
senddmabufmask[0]);
ipath_write_kreg(dd, dd->ipath_kregs->kr_senddmabufmask1,
@@ -615,6 +632,9 @@ void ipath_restart_sdma(struct ipath_devdata *dd)
ipath_read_kreg64(dd, dd->ipath_kregs->kr_scratch);
spin_unlock_irqrestore(&dd->ipath_sendctrl_lock, flags);
+ /* notify upper layers */
+ ipath_ib_piobufavail(dd->verbs_dev);
+
bail:
return;
}
diff --git a/drivers/infiniband/hw/ipath/ipath_verbs.c b/drivers/infiniband/hw/ipath/ipath_verbs.c
index e63927cce5b..5015cd2e57b 100644
--- a/drivers/infiniband/hw/ipath/ipath_verbs.c
+++ b/drivers/infiniband/hw/ipath/ipath_verbs.c
@@ -396,7 +396,6 @@ static int ipath_post_one_send(struct ipath_qp *qp, struct ib_send_wr *wr)
wqe = get_swqe_ptr(qp, qp->s_head);
wqe->wr = *wr;
- wqe->ssn = qp->s_ssn++;
wqe->length = 0;
if (wr->num_sge) {
acc = wr->opcode >= IB_WR_RDMA_READ ?
@@ -422,6 +421,7 @@ static int ipath_post_one_send(struct ipath_qp *qp, struct ib_send_wr *wr)
goto bail_inval;
} else if (wqe->length > to_idev(qp->ibqp.device)->dd->ipath_ibmtu)
goto bail_inval;
+ wqe->ssn = qp->s_ssn++;
qp->s_head = next;
ret = 0;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 5938fa96292..faf3d891297 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -886,7 +886,7 @@ static int make_request(struct request_queue *q, struct bio * bio)
*/
raid10_find_phys(conf, r10_bio);
retry_write:
- blocked_rdev = 0;
+ blocked_rdev = NULL;
rcu_read_lock();
for (i = 0; i < conf->copies; i++) {
int d = r10_bio->devs[i].devnum;
diff --git a/drivers/media/Makefile b/drivers/media/Makefile
index 73f742c7e81..cc11c4c0e7e 100644
--- a/drivers/media/Makefile
+++ b/drivers/media/Makefile
@@ -2,6 +2,8 @@
# Makefile for the kernel multimedia device drivers.
#
+obj-y := common/
+
obj-$(CONFIG_VIDEO_MEDIA) += common/
# Since hybrid devices are here, should be compiled if DVB and/or V4L
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index 8f5ed9b4bf8..3f55d47bc4b 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -613,7 +613,7 @@ static int __devinit cx18_probe(struct pci_dev *dev,
}
cx = kzalloc(sizeof(struct cx18), GFP_ATOMIC);
- if (cx == 0) {
+ if (!cx) {
spin_unlock(&cx18_cards_lock);
return -ENOMEM;
}
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index a0baf2d0ba7..48e1a01718e 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -1634,7 +1634,7 @@ static int saa7134_s_fmt_overlay(struct file *file, void *priv,
struct saa7134_fh *fh = priv;
struct saa7134_dev *dev = fh->dev;
int err;
- unsigned int flags;
+ unsigned long flags;
if (saa7134_no_overlay > 0) {
printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index a873d2b315c..a7714da7c28 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -100,7 +100,9 @@ static int nsc_ircc_probe_39x(nsc_chip_t *chip, chipio_t *info);
static int nsc_ircc_init_108(nsc_chip_t *chip, chipio_t *info);
static int nsc_ircc_init_338(nsc_chip_t *chip, chipio_t *info);
static int nsc_ircc_init_39x(nsc_chip_t *chip, chipio_t *info);
+#ifdef CONFIG_PNP
static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id);
+#endif
/* These are the known NSC chips */
static nsc_chip_t chips[] = {
@@ -156,9 +158,11 @@ static const struct pnp_device_id nsc_ircc_pnp_table[] = {
MODULE_DEVICE_TABLE(pnp, nsc_ircc_pnp_table);
static struct pnp_driver nsc_ircc_pnp_driver = {
+#ifdef CONFIG_PNP
.name = "nsc-ircc",
.id_table = nsc_ircc_pnp_table,
.probe = nsc_ircc_pnp_probe,
+#endif
};
/* Some prototypes */
@@ -916,6 +920,7 @@ static int nsc_ircc_probe_39x(nsc_chip_t *chip, chipio_t *info)
return 0;
}
+#ifdef CONFIG_PNP
/* PNP probing */
static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *id)
{
@@ -952,6 +957,7 @@ static int nsc_ircc_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *i
return 0;
}
+#endif
/*
* Function nsc_ircc_setup (info)
diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c
index 1f26da761e9..cfe0194fef7 100644
--- a/drivers/net/irda/smsc-ircc2.c
+++ b/drivers/net/irda/smsc-ircc2.c
@@ -376,6 +376,7 @@ MODULE_DEVICE_TABLE(pnp, smsc_ircc_pnp_table);
static int pnp_driver_registered;
+#ifdef CONFIG_PNP
static int __init smsc_ircc_pnp_probe(struct pnp_dev *dev,
const struct pnp_device_id *dev_id)
{
@@ -402,7 +403,9 @@ static struct pnp_driver smsc_ircc_pnp_driver = {
.id_table = smsc_ircc_pnp_table,
.probe = smsc_ircc_pnp_probe,
};
-
+#else /* CONFIG_PNP */
+static struct pnp_driver smsc_ircc_pnp_driver;
+#endif
/*******************************************************************************
*
diff --git a/drivers/net/niu.c b/drivers/net/niu.c
index 4009c4ce96b..57cfd72ffdf 100644
--- a/drivers/net/niu.c
+++ b/drivers/net/niu.c
@@ -1,6 +1,6 @@
/* niu.c: Neptune ethernet driver.
*
- * Copyright (C) 2007 David S. Miller (davem@davemloft.net)
+ * Copyright (C) 2007, 2008 David S. Miller (davem@davemloft.net)
*/
#include <linux/module.h>
@@ -33,8 +33,8 @@
#define DRV_MODULE_NAME "niu"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "0.8"
-#define DRV_MODULE_RELDATE "April 24, 2008"
+#define DRV_MODULE_VERSION "0.9"
+#define DRV_MODULE_RELDATE "May 4, 2008"
static char version[] __devinitdata =
DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
@@ -7264,8 +7264,11 @@ static int __devinit niu_get_and_validate_port(struct niu *np)
parent->num_ports = nr64(ESPC_NUM_PORTS_MACS) &
ESPC_NUM_PORTS_MACS_VAL;
+ /* All of the current probing methods fail on
+ * Maramba on-board parts.
+ */
if (!parent->num_ports)
- return -ENODEV;
+ parent->num_ports = 4;
}
}
}
diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c
index 6f245cfb662..dc6f097062d 100644
--- a/drivers/net/usb/asix.c
+++ b/drivers/net/usb/asix.c
@@ -1381,6 +1381,10 @@ static const struct usb_device_id products [] = {
USB_DEVICE (0x0411, 0x003d),
.driver_info = (unsigned long) &ax8817x_info,
}, {
+ // Buffalo LUA-U2-GT 10/100/1000
+ USB_DEVICE (0x0411, 0x006e),
+ .driver_info = (unsigned long) &ax88178_info,
+}, {
// Sitecom LN-029 "USB 2.0 10/100 Ethernet adapter"
USB_DEVICE (0x6189, 0x182d),
.driver_info = (unsigned long) &ax8817x_info,
diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c
index b5860b97a93..24fd613466b 100644
--- a/drivers/net/wan/lapbether.c
+++ b/drivers/net/wan/lapbether.c
@@ -459,6 +459,7 @@ static void __exit lapbeth_cleanup_driver(void)
list_for_each_safe(entry, tmp, &lapbeth_devices) {
lapbeth = list_entry(entry, struct lapbethdev, node);
+ dev_put(lapbeth->ethdev);
unregister_netdevice(lapbeth->axdev);
}
rtnl_unlock();
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index d5b7a76fcaa..62fb89d8231 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -1,6 +1,5 @@
config IWLWIFI
- bool
- default n
+ tristate
config IWLCORE
tristate "Intel Wireless Wifi Core"
diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c
index a83a40b3eba..0f0d27d1c4c 100644
--- a/drivers/rtc/rtc-ds1511.c
+++ b/drivers/rtc/rtc-ds1511.c
@@ -184,7 +184,7 @@ ds1511_wdog_disable(void)
static int ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
{
u8 mon, day, dow, hrs, min, sec, yrs, cen;
- unsigned int flags;
+ unsigned long flags;
/*
* won't have to change this for a while
@@ -247,7 +247,7 @@ static int ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
static int ds1511_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
{
unsigned int century;
- unsigned int flags;
+ unsigned long flags;
spin_lock_irqsave(&ds1511_lock, flags);
rtc_disable_update();
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index c1f2adefad4..5043150019a 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -965,8 +965,7 @@ tty3270_write_room(struct tty_struct *tty)
* Insert character into the screen at the current position with the
* current color and highlight. This function does NOT do cursor movement.
*/
-static int
-tty3270_put_character(struct tty3270 *tp, char ch)
+static void tty3270_put_character(struct tty3270 *tp, char ch)
{
struct tty3270_line *line;
struct tty3270_cell *cell;
@@ -986,7 +985,6 @@ tty3270_put_character(struct tty3270 *tp, char ch)
cell->character = tp->view.ascebc[(unsigned int) ch];
cell->highlight = tp->highlight;
cell->f_color = tp->f_color;
- return 1;
}
/*
@@ -1612,16 +1610,15 @@ tty3270_write(struct tty_struct * tty,
/*
* Put single characters to the ttys character buffer
*/
-static void
-tty3270_put_char(struct tty_struct *tty, unsigned char ch)
+static int tty3270_put_char(struct tty_struct *tty, unsigned char ch)
{
struct tty3270 *tp;
tp = tty->driver_data;
- if (!tp)
- return;
- if (tp->char_count < TTY3270_CHAR_BUF_SIZE)
- tp->char_buf[tp->char_count++] = ch;
+ if (!tp || tp->char_count >= TTY3270_CHAR_BUF_SIZE)
+ return 0;
+ tp->char_buf[tp->char_count++] = ch;
+ return 1;
}
/*
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
index 40ef948fcb3..9c21b8f43f9 100644
--- a/drivers/s390/cio/blacklist.c
+++ b/drivers/s390/cio/blacklist.c
@@ -19,6 +19,7 @@
#include <asm/cio.h>
#include <asm/uaccess.h>
+#include <asm/cio.h>
#include "blacklist.h"
#include "cio.h"
@@ -43,164 +44,169 @@ typedef enum {add, free} range_action;
* Function: blacklist_range
* (Un-)blacklist the devices from-to
*/
-static void
-blacklist_range (range_action action, unsigned int from, unsigned int to,
- unsigned int ssid)
+static int blacklist_range(range_action action, unsigned int from_ssid,
+ unsigned int to_ssid, unsigned int from,
+ unsigned int to, int msgtrigger)
{
- if (!to)
- to = from;
-
- if (from > to || to > __MAX_SUBCHANNEL || ssid > __MAX_SSID) {
- printk (KERN_WARNING "cio: Invalid blacklist range "
- "0.%x.%04x to 0.%x.%04x, skipping\n",
- ssid, from, ssid, to);
- return;
+ if ((from_ssid > to_ssid) || ((from_ssid == to_ssid) && (from > to))) {
+ if (msgtrigger)
+ printk(KERN_WARNING "cio: Invalid cio_ignore range "
+ "0.%x.%04x-0.%x.%04x\n", from_ssid, from,
+ to_ssid, to);
+ return 1;
}
- for (; from <= to; from++) {
+
+ while ((from_ssid < to_ssid) || ((from_ssid == to_ssid) &&
+ (from <= to))) {
if (action == add)
- set_bit (from, bl_dev[ssid]);
+ set_bit(from, bl_dev[from_ssid]);
else
- clear_bit (from, bl_dev[ssid]);
+ clear_bit(from, bl_dev[from_ssid]);
+ from++;
+ if (from > __MAX_SUBCHANNEL) {
+ from_ssid++;
+ from = 0;
+ }
}
+
+ return 0;
}
-/*
- * Function: blacklist_busid
- * Get devno/busid from given string.
- * Shamelessly grabbed from dasd_devmap.c.
- */
-static int
-blacklist_busid(char **str, int *id0, int *ssid, int *devno)
+static int pure_hex(char **cp, unsigned int *val, int min_digit,
+ int max_digit, int max_val)
{
- int val, old_style;
- char *sav;
+ int diff;
+ unsigned int value;
- sav = *str;
+ diff = 0;
+ *val = 0;
- /* check for leading '0x' */
- old_style = 0;
- if ((*str)[0] == '0' && (*str)[1] == 'x') {
- *str += 2;
- old_style = 1;
- }
- if (!isxdigit((*str)[0])) /* We require at least one hex digit */
- goto confused;
- val = simple_strtoul(*str, str, 16);
- if (old_style || (*str)[0] != '.') {
- *id0 = *ssid = 0;
- if (val < 0 || val > 0xffff)
- goto confused;
- *devno = val;
- if ((*str)[0] != ',' && (*str)[0] != '-' &&
- (*str)[0] != '\n' && (*str)[0] != '\0')
- goto confused;
- return 0;
+ while (isxdigit(**cp) && (diff <= max_digit)) {
+
+ if (isdigit(**cp))
+ value = **cp - '0';
+ else
+ value = tolower(**cp) - 'a' + 10;
+ *val = *val * 16 + value;
+ (*cp)++;
+ diff++;
}
- /* New style x.y.z busid */
- if (val < 0 || val > 0xff)
- goto confused;
- *id0 = val;
- (*str)++;
- if (!isxdigit((*str)[0])) /* We require at least one hex digit */
- goto confused;
- val = simple_strtoul(*str, str, 16);
- if (val < 0 || val > 0xff || (*str)++[0] != '.')
- goto confused;
- *ssid = val;
- if (!isxdigit((*str)[0])) /* We require at least one hex digit */
- goto confused;
- val = simple_strtoul(*str, str, 16);
- if (val < 0 || val > 0xffff)
- goto confused;
- *devno = val;
- if ((*str)[0] != ',' && (*str)[0] != '-' &&
- (*str)[0] != '\n' && (*str)[0] != '\0')
- goto confused;
+
+ if ((diff < min_digit) || (diff > max_digit) || (*val > max_val))
+ return 1;
+
return 0;
-confused:
- strsep(str, ",\n");
- printk(KERN_WARNING "cio: Invalid cio_ignore parameter '%s'\n", sav);
- return 1;
}
-static int
-blacklist_parse_parameters (char *str, range_action action)
+static int parse_busid(char *str, int *cssid, int *ssid, int *devno,
+ int msgtrigger)
{
- int from, to, from_id0, to_id0, from_ssid, to_ssid;
-
- while (*str != 0 && *str != '\n') {
- range_action ra = action;
- while(*str == ',')
- str++;
- if (*str == '!') {
- ra = !action;
- ++str;
+ char *str_work;
+ int val, rc, ret;
+
+ rc = 1;
+
+ if (*str == '\0')
+ goto out;
+
+ /* old style */
+ str_work = str;
+ val = simple_strtoul(str, &str_work, 16);
+
+ if (*str_work == '\0') {
+ if (val <= __MAX_SUBCHANNEL) {
+ *devno = val;
+ *ssid = 0;
+ *cssid = 0;
+ rc = 0;
}
+ goto out;
+ }
- /*
- * Since we have to parse the proc commands and the
- * kernel arguments we have to check four cases
- */
- if (strncmp(str,"all,",4) == 0 || strcmp(str,"all") == 0 ||
- strncmp(str,"all\n",4) == 0 || strncmp(str,"all ",4) == 0) {
- int j;
-
- str += 3;
- for (j=0; j <= __MAX_SSID; j++)
- blacklist_range(ra, 0, __MAX_SUBCHANNEL, j);
- } else {
- int rc;
+ /* new style */
+ str_work = str;
+ ret = pure_hex(&str_work, cssid, 1, 2, __MAX_CSSID);
+ if (ret || (str_work[0] != '.'))
+ goto out;
+ str_work++;
+ ret = pure_hex(&str_work, ssid, 1, 1, __MAX_SSID);
+ if (ret || (str_work[0] != '.'))
+ goto out;
+ str_work++;
+ ret = pure_hex(&str_work, devno, 4, 4, __MAX_SUBCHANNEL);
+ if (ret || (str_work[0] != '\0'))
+ goto out;
+
+ rc = 0;
+out:
+ if (rc && msgtrigger)
+ printk(KERN_WARNING "cio: Invalid cio_ignore device '%s'\n",
+ str);
+
+ return rc;
+}
- rc = blacklist_busid(&str, &from_id0,
- &from_ssid, &from);
- if (rc)
- continue;
- to = from;
- to_id0 = from_id0;
- to_ssid = from_ssid;
- if (*str == '-') {
- str++;
- rc = blacklist_busid(&str, &to_id0,
- &to_ssid, &to);
- if (rc)
- continue;
- }
- if (*str == '-') {
- printk(KERN_WARNING "cio: invalid cio_ignore "
- "parameter '%s'\n",
- strsep(&str, ",\n"));
- continue;
- }
- if ((from_id0 != to_id0) ||
- (from_ssid != to_ssid)) {
- printk(KERN_WARNING "cio: invalid cio_ignore "
- "range %x.%x.%04x-%x.%x.%04x\n",
- from_id0, from_ssid, from,
- to_id0, to_ssid, to);
- continue;
+static int blacklist_parse_parameters(char *str, range_action action,
+ int msgtrigger)
+{
+ int from_cssid, to_cssid, from_ssid, to_ssid, from, to;
+ int rc, totalrc;
+ char *parm;
+ range_action ra;
+
+ totalrc = 0;
+
+ while ((parm = strsep(&str, ","))) {
+ rc = 0;
+ ra = action;
+ if (*parm == '!') {
+ if (ra == add)
+ ra = free;
+ else
+ ra = add;
+ parm++;
+ }
+ if (strcmp(parm, "all") == 0) {
+ from_cssid = 0;
+ from_ssid = 0;
+ from = 0;
+ to_cssid = __MAX_CSSID;
+ to_ssid = __MAX_SSID;
+ to = __MAX_SUBCHANNEL;
+ } else {
+ rc = parse_busid(strsep(&parm, "-"), &from_cssid,
+ &from_ssid, &from, msgtrigger);
+ if (!rc) {
+ if (parm != NULL)
+ rc = parse_busid(parm, &to_cssid,
+ &to_ssid, &to,
+ msgtrigger);
+ else {
+ to_cssid = from_cssid;
+ to_ssid = from_ssid;
+ to = from;
+ }
}
- blacklist_range (ra, from, to, to_ssid);
}
+ if (!rc) {
+ rc = blacklist_range(ra, from_ssid, to_ssid, from, to,
+ msgtrigger);
+ if (rc)
+ totalrc = 1;
+ } else
+ totalrc = 1;
}
- return 1;
+
+ return totalrc;
}
-/* Parsing the commandline for blacklist parameters, e.g. to blacklist
- * bus ids 0.0.1234, 0.0.1235 and 0.0.1236, you could use any of:
- * - cio_ignore=1234-1236
- * - cio_ignore=0x1234-0x1235,1236
- * - cio_ignore=0x1234,1235-1236
- * - cio_ignore=1236 cio_ignore=1234-0x1236
- * - cio_ignore=1234 cio_ignore=1236 cio_ignore=0x1235
- * - cio_ignore=0.0.1234-0.0.1236
- * - cio_ignore=0.0.1234,0x1235,1236
- * - ...
- */
static int __init
blacklist_setup (char *str)
{
CIO_MSG_EVENT(6, "Reading blacklist parameters\n");
- return blacklist_parse_parameters (str, add);
+ if (blacklist_parse_parameters(str, add, 1))
+ return 0;
+ return 1;
}
__setup ("cio_ignore=", blacklist_setup);
@@ -224,27 +230,23 @@ is_blacklisted (int ssid, int devno)
* Function: blacklist_parse_proc_parameters
* parse the stuff which is piped to /proc/cio_ignore
*/
-static void
-blacklist_parse_proc_parameters (char *buf)
+static int blacklist_parse_proc_parameters(char *buf)
{
- if (strncmp (buf, "free ", 5) == 0) {
- blacklist_parse_parameters (buf + 5, free);
- } else if (strncmp (buf, "add ", 4) == 0) {
- /*
- * We don't need to check for known devices since
- * css_probe_device will handle this correctly.
- */
- blacklist_parse_parameters (buf + 4, add);
- } else {
- printk (KERN_WARNING "cio: cio_ignore: Parse error; \n"
- KERN_WARNING "try using 'free all|<devno-range>,"
- "<devno-range>,...'\n"
- KERN_WARNING "or 'add <devno-range>,"
- "<devno-range>,...'\n");
- return;
- }
+ int rc;
+ char *parm;
+
+ parm = strsep(&buf, " ");
+
+ if (strcmp("free", parm) == 0)
+ rc = blacklist_parse_parameters(buf, free, 0);
+ else if (strcmp("add", parm) == 0)
+ rc = blacklist_parse_parameters(buf, add, 0);
+ else
+ return 1;
css_schedule_reprobe();
+
+ return rc;
}
/* Iterator struct for all devices. */
@@ -328,6 +330,8 @@ cio_ignore_write(struct file *file, const char __user *user_buf,
size_t user_len, loff_t *offset)
{
char *buf;
+ size_t i;
+ ssize_t rc, ret;
if (*offset)
return -EINVAL;
@@ -336,16 +340,27 @@ cio_ignore_write(struct file *file, const char __user *user_buf,
buf = vmalloc (user_len + 1); /* maybe better use the stack? */
if (buf == NULL)
return -ENOMEM;
+ memset(buf, 0, user_len + 1);
+
if (strncpy_from_user (buf, user_buf, user_len) < 0) {
- vfree (buf);
- return -EFAULT;
+ rc = -EFAULT;
+ goto out_free;
}
- buf[user_len] = '\0';
- blacklist_parse_proc_parameters (buf);
+ i = user_len - 1;
+ while ((i >= 0) && (isspace(buf[i]) || (buf[i] == 0))) {
+ buf[i] = '\0';
+ i--;
+ }
+ ret = blacklist_parse_proc_parameters(buf);
+ if (ret)
+ rc = -EINVAL;
+ else
+ rc = user_len;
+out_free:
vfree (buf);
- return user_len;
+ return rc;
}
static const struct seq_operations cio_ignore_proc_seq_ops = {
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 08a57816130..82c6a2d4512 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -39,23 +39,6 @@ debug_info_t *cio_debug_msg_id;
debug_info_t *cio_debug_trace_id;
debug_info_t *cio_debug_crw_id;
-int cio_show_msg;
-
-static int __init
-cio_setup (char *parm)
-{
- if (!strcmp (parm, "yes"))
- cio_show_msg = 1;
- else if (!strcmp (parm, "no"))
- cio_show_msg = 0;
- else
- printk(KERN_ERR "cio: cio_setup: "
- "invalid cio_msg parameter '%s'", parm);
- return 1;
-}
-
-__setup ("cio_msg=", cio_setup);
-
/*
* Function: cio_debug_init
* Initializes three debug logs for common I/O:
@@ -166,7 +149,7 @@ cio_start_handle_notoper(struct subchannel *sch, __u8 lpm)
stsch (sch->schid, &sch->schib);
- CIO_MSG_EVENT(0, "cio_start: 'not oper' status for "
+ CIO_MSG_EVENT(2, "cio_start: 'not oper' status for "
"subchannel 0.%x.%04x!\n", sch->schid.ssid,
sch->schid.sch_no);
sprintf(dbf_text, "no%s", sch->dev.bus_id);
@@ -567,10 +550,9 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
* ... just being curious we check for non I/O subchannels
*/
if (sch->st != 0) {
- CIO_DEBUG(KERN_INFO, 0,
- "Subchannel 0.%x.%04x reports "
- "non-I/O subchannel type %04X\n",
- sch->schid.ssid, sch->schid.sch_no, sch->st);
+ CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports "
+ "non-I/O subchannel type %04X\n",
+ sch->schid.ssid, sch->schid.sch_no, sch->st);
/* We stop here for non-io subchannels. */
err = sch->st;
goto out;
@@ -588,7 +570,7 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
* This device must not be known to Linux. So we simply
* say that there is no device and return ENODEV.
*/
- CIO_MSG_EVENT(4, "Blacklisted device detected "
+ CIO_MSG_EVENT(6, "Blacklisted device detected "
"at devno %04X, subchannel set %x\n",
sch->schib.pmcw.dev, sch->schid.ssid);
err = -ENODEV;
@@ -601,12 +583,11 @@ cio_validate_subchannel (struct subchannel *sch, struct subchannel_id schid)
sch->lpm = sch->schib.pmcw.pam & sch->opm;
sch->isc = 3;
- CIO_DEBUG(KERN_INFO, 0,
- "Detected device %04x on subchannel 0.%x.%04X"
- " - PIM = %02X, PAM = %02X, POM = %02X\n",
- sch->schib.pmcw.dev, sch->schid.ssid,
- sch->schid.sch_no, sch->schib.pmcw.pim,
- sch->schib.pmcw.pam, sch->schib.pmcw.pom);
+ CIO_MSG_EVENT(6, "Detected device %04x on subchannel 0.%x.%04X "
+ "- PIM = %02X, PAM = %02X, POM = %02X\n",
+ sch->schib.pmcw.dev, sch->schid.ssid,
+ sch->schid.sch_no, sch->schib.pmcw.pim,
+ sch->schib.pmcw.pam, sch->schib.pmcw.pom);
/*
* We now have to initially ...
diff --git a/drivers/s390/cio/cio.h b/drivers/s390/cio/cio.h
index 3c75412904d..6e933aebe01 100644
--- a/drivers/s390/cio/cio.h
+++ b/drivers/s390/cio/cio.h
@@ -118,6 +118,4 @@ extern void *cio_get_console_priv(void);
#define cio_get_console_priv() NULL
#endif
-extern int cio_show_msg;
-
#endif
diff --git a/drivers/s390/cio/cio_debug.h b/drivers/s390/cio/cio_debug.h
index d7429ef6c66..e64e8278c42 100644
--- a/drivers/s390/cio/cio_debug.h
+++ b/drivers/s390/cio/cio_debug.h
@@ -31,10 +31,4 @@ static inline void CIO_HEX_EVENT(int level, void *data, int length)
}
}
-#define CIO_DEBUG(printk_level, event_level, msg...) do { \
- if (cio_show_msg) \
- printk(printk_level "cio: " msg); \
- CIO_MSG_EVENT(event_level, msg); \
- } while (0)
-
#endif
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 595e327d2f7..a76956512b2 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -570,7 +570,7 @@ static void reprobe_all(struct work_struct *unused)
{
int ret;
- CIO_MSG_EVENT(2, "reprobe start\n");
+ CIO_MSG_EVENT(4, "reprobe start\n");
need_reprobe = 0;
/* Make sure initial subchannel scan is done. */
@@ -578,7 +578,7 @@ static void reprobe_all(struct work_struct *unused)
atomic_read(&ccw_device_init_count) == 0);
ret = for_each_subchannel_staged(NULL, reprobe_subchannel, NULL);
- CIO_MSG_EVENT(2, "reprobe done (rc=%d, need_reprobe=%d)\n", ret,
+ CIO_MSG_EVENT(4, "reprobe done (rc=%d, need_reprobe=%d)\n", ret,
need_reprobe);
}
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index abfd601d237..e22813db74a 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -341,7 +341,7 @@ ccw_device_remove_disconnected(struct ccw_device *cdev)
rc = device_schedule_callback(&cdev->dev,
ccw_device_remove_orphan_cb);
if (rc)
- CIO_MSG_EVENT(2, "Couldn't unregister orphan "
+ CIO_MSG_EVENT(0, "Couldn't unregister orphan "
"0.%x.%04x\n",
cdev->private->dev_id.ssid,
cdev->private->dev_id.devno);
@@ -351,7 +351,7 @@ ccw_device_remove_disconnected(struct ccw_device *cdev)
rc = device_schedule_callback(cdev->dev.parent,
ccw_device_remove_sch_cb);
if (rc)
- CIO_MSG_EVENT(2, "Couldn't unregister disconnected device "
+ CIO_MSG_EVENT(0, "Couldn't unregister disconnected device "
"0.%x.%04x\n",
cdev->private->dev_id.ssid,
cdev->private->dev_id.devno);
@@ -397,7 +397,7 @@ int ccw_device_set_offline(struct ccw_device *cdev)
if (ret == 0)
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
else {
- CIO_MSG_EVENT(2, "ccw_device_offline returned %d, "
+ CIO_MSG_EVENT(0, "ccw_device_offline returned %d, "
"device 0.%x.%04x\n",
ret, cdev->private->dev_id.ssid,
cdev->private->dev_id.devno);
@@ -433,7 +433,7 @@ int ccw_device_set_online(struct ccw_device *cdev)
if (ret == 0)
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
else {
- CIO_MSG_EVENT(2, "ccw_device_online returned %d, "
+ CIO_MSG_EVENT(0, "ccw_device_online returned %d, "
"device 0.%x.%04x\n",
ret, cdev->private->dev_id.ssid,
cdev->private->dev_id.devno);
@@ -451,7 +451,7 @@ int ccw_device_set_online(struct ccw_device *cdev)
if (ret == 0)
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
else
- CIO_MSG_EVENT(2, "ccw_device_offline returned %d, "
+ CIO_MSG_EVENT(0, "ccw_device_offline returned %d, "
"device 0.%x.%04x\n",
ret, cdev->private->dev_id.ssid,
cdev->private->dev_id.devno);
@@ -803,7 +803,7 @@ static void sch_attach_disconnected_device(struct subchannel *sch,
other_sch = to_subchannel(get_device(cdev->dev.parent));
ret = device_move(&cdev->dev, &sch->dev);
if (ret) {
- CIO_MSG_EVENT(2, "Moving disconnected device 0.%x.%04x failed "
+ CIO_MSG_EVENT(0, "Moving disconnected device 0.%x.%04x failed "
"(ret=%d)!\n", cdev->private->dev_id.ssid,
cdev->private->dev_id.devno, ret);
put_device(&other_sch->dev);
@@ -933,7 +933,7 @@ io_subchannel_register(struct work_struct *work)
ret = device_reprobe(&cdev->dev);
if (ret)
/* We can't do much here. */
- CIO_MSG_EVENT(2, "device_reprobe() returned"
+ CIO_MSG_EVENT(0, "device_reprobe() returned"
" %d for 0.%x.%04x\n", ret,
cdev->private->dev_id.ssid,
cdev->private->dev_id.devno);
@@ -1086,7 +1086,7 @@ static void ccw_device_move_to_sch(struct work_struct *work)
rc = device_move(&cdev->dev, &sch->dev);
mutex_unlock(&sch->reg_mutex);
if (rc) {
- CIO_MSG_EVENT(2, "Moving device 0.%x.%04x to subchannel "
+ CIO_MSG_EVENT(0, "Moving device 0.%x.%04x to subchannel "
"0.%x.%04x failed (ret=%d)!\n",
cdev->private->dev_id.ssid,
cdev->private->dev_id.devno, sch->schid.ssid,
@@ -1446,8 +1446,7 @@ ccw_device_remove (struct device *dev)
wait_event(cdev->private->wait_q,
dev_fsm_final_state(cdev));
else
- //FIXME: we can't fail!
- CIO_MSG_EVENT(2, "ccw_device_offline returned %d, "
+ CIO_MSG_EVENT(0, "ccw_device_offline returned %d, "
"device 0.%x.%04x\n",
ret, cdev->private->dev_id.ssid,
cdev->private->dev_id.devno);
@@ -1524,7 +1523,7 @@ static int recovery_check(struct device *dev, void *data)
spin_lock_irq(cdev->ccwlock);
switch (cdev->private->state) {
case DEV_STATE_DISCONNECTED:
- CIO_MSG_EVENT(3, "recovery: trigger 0.%x.%04x\n",
+ CIO_MSG_EVENT(4, "recovery: trigger 0.%x.%04x\n",
cdev->private->dev_id.ssid,
cdev->private->dev_id.devno);
dev_fsm_event(cdev, DEV_EVENT_VERIFY);
@@ -1554,7 +1553,7 @@ static void recovery_work_func(struct work_struct *unused)
}
spin_unlock_irq(&recovery_lock);
} else
- CIO_MSG_EVENT(2, "recovery: end\n");
+ CIO_MSG_EVENT(4, "recovery: end\n");
}
static DECLARE_WORK(recovery_work, recovery_work_func);
@@ -1572,7 +1571,7 @@ void ccw_device_schedule_recovery(void)
{
unsigned long flags;
- CIO_MSG_EVENT(2, "recovery: schedule\n");
+ CIO_MSG_EVENT(4, "recovery: schedule\n");
spin_lock_irqsave(&recovery_lock, flags);
if (!timer_pending(&recovery_timer) || (recovery_phase != 0)) {
recovery_phase = 0;
diff --git a/drivers/s390/cio/device_fsm.c b/drivers/s390/cio/device_fsm.c
index 99403b0a97a..e268d5a77c1 100644
--- a/drivers/s390/cio/device_fsm.c
+++ b/drivers/s390/cio/device_fsm.c
@@ -322,10 +322,10 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
same_dev = 0; /* Keep the compiler quiet... */
switch (state) {
case DEV_STATE_NOT_OPER:
- CIO_DEBUG(KERN_WARNING, 2,
- "SenseID : unknown device %04x on subchannel "
- "0.%x.%04x\n", cdev->private->dev_id.devno,
- sch->schid.ssid, sch->schid.sch_no);
+ CIO_MSG_EVENT(2, "SenseID : unknown device %04x on "
+ "subchannel 0.%x.%04x\n",
+ cdev->private->dev_id.devno,
+ sch->schid.ssid, sch->schid.sch_no);
break;
case DEV_STATE_OFFLINE:
if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID) {
@@ -348,20 +348,19 @@ ccw_device_recog_done(struct ccw_device *cdev, int state)
return;
}
/* Issue device info message. */
- CIO_DEBUG(KERN_INFO, 2,
- "SenseID : device 0.%x.%04x reports: "
- "CU Type/Mod = %04X/%02X, Dev Type/Mod = "
- "%04X/%02X\n",
- cdev->private->dev_id.ssid,
- cdev->private->dev_id.devno,
- cdev->id.cu_type, cdev->id.cu_model,
- cdev->id.dev_type, cdev->id.dev_model);
+ CIO_MSG_EVENT(4, "SenseID : device 0.%x.%04x reports: "
+ "CU Type/Mod = %04X/%02X, Dev Type/Mod = "
+ "%04X/%02X\n",
+ cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno,
+ cdev->id.cu_type, cdev->id.cu_model,
+ cdev->id.dev_type, cdev->id.dev_model);
break;
case DEV_STATE_BOXED:
- CIO_DEBUG(KERN_WARNING, 2,
- "SenseID : boxed device %04x on subchannel "
- "0.%x.%04x\n", cdev->private->dev_id.devno,
- sch->schid.ssid, sch->schid.sch_no);
+ CIO_MSG_EVENT(0, "SenseID : boxed device %04x on "
+ " subchannel 0.%x.%04x\n",
+ cdev->private->dev_id.devno,
+ sch->schid.ssid, sch->schid.sch_no);
break;
}
cdev->private->state = state;
@@ -443,9 +442,8 @@ ccw_device_done(struct ccw_device *cdev, int state)
if (state == DEV_STATE_BOXED)
- CIO_DEBUG(KERN_WARNING, 2,
- "Boxed device %04x on subchannel %04x\n",
- cdev->private->dev_id.devno, sch->schid.sch_no);
+ CIO_MSG_EVENT(0, "Boxed device %04x on subchannel %04x\n",
+ cdev->private->dev_id.devno, sch->schid.sch_no);
if (cdev->private->flags.donotify) {
cdev->private->flags.donotify = 0;
@@ -900,7 +898,7 @@ ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event)
/* Basic sense hasn't started. Try again. */
ccw_device_do_sense(cdev, irb);
else {
- CIO_MSG_EVENT(2, "Huh? 0.%x.%04x: unsolicited "
+ CIO_MSG_EVENT(0, "0.%x.%04x: unsolicited "
"interrupt during w4sense...\n",
cdev->private->dev_id.ssid,
cdev->private->dev_id.devno);
@@ -1169,8 +1167,10 @@ ccw_device_nop(struct ccw_device *cdev, enum dev_event dev_event)
static void
ccw_device_bug(struct ccw_device *cdev, enum dev_event dev_event)
{
- CIO_MSG_EVENT(0, "dev_jumptable[%i][%i] == NULL\n",
- cdev->private->state, dev_event);
+ CIO_MSG_EVENT(0, "Internal state [%i][%i] not handled for device "
+ "0.%x.%04x\n", cdev->private->state, dev_event,
+ cdev->private->dev_id.ssid,
+ cdev->private->dev_id.devno);
BUG();
}
diff --git a/drivers/s390/cio/device_id.c b/drivers/s390/cio/device_id.c
index dc4d87f77f6..cba7020517e 100644
--- a/drivers/s390/cio/device_id.c
+++ b/drivers/s390/cio/device_id.c
@@ -214,7 +214,7 @@ ccw_device_check_sense_id(struct ccw_device *cdev)
* sense id information. So, for intervention required,
* we use the "whack it until it talks" strategy...
*/
- CIO_MSG_EVENT(2, "SenseID : device %04x on Subchannel "
+ CIO_MSG_EVENT(0, "SenseID : device %04x on Subchannel "
"0.%x.%04x reports cmd reject\n",
cdev->private->dev_id.devno, sch->schid.ssid,
sch->schid.sch_no);
@@ -239,7 +239,7 @@ ccw_device_check_sense_id(struct ccw_device *cdev)
lpm = to_io_private(sch)->orb.lpm;
if ((lpm & sch->schib.pmcw.pim & sch->schib.pmcw.pam) != 0)
- CIO_MSG_EVENT(2, "SenseID : path %02X for device %04x "
+ CIO_MSG_EVENT(4, "SenseID : path %02X for device %04x "
"on subchannel 0.%x.%04x is "
"'not operational'\n", lpm,
cdev->private->dev_id.devno,
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c
index c52449a1f9f..ba559053402 100644
--- a/drivers/s390/cio/device_pgid.c
+++ b/drivers/s390/cio/device_pgid.c
@@ -79,7 +79,7 @@ __ccw_device_sense_pgid_start(struct ccw_device *cdev)
/* ret is 0, -EBUSY, -EACCES or -ENODEV */
if (ret != -EACCES)
return ret;
- CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel "
+ CIO_MSG_EVENT(3, "SNID - Device %04x on Subchannel "
"0.%x.%04x, lpm %02X, became 'not "
"operational'\n",
cdev->private->dev_id.devno,
@@ -159,7 +159,7 @@ __ccw_device_check_sense_pgid(struct ccw_device *cdev)
u8 lpm;
lpm = to_io_private(sch)->orb.lpm;
- CIO_MSG_EVENT(2, "SNID - Device %04x on Subchannel 0.%x.%04x,"
+ CIO_MSG_EVENT(3, "SNID - Device %04x on Subchannel 0.%x.%04x,"
" lpm %02X, became 'not operational'\n",
cdev->private->dev_id.devno, sch->schid.ssid,
sch->schid.sch_no, lpm);
@@ -275,7 +275,7 @@ __ccw_device_do_pgid(struct ccw_device *cdev, __u8 func)
return ret;
}
/* PGID command failed on this path. */
- CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel "
+ CIO_MSG_EVENT(3, "SPID - Device %04x on Subchannel "
"0.%x.%04x, lpm %02X, became 'not operational'\n",
cdev->private->dev_id.devno, sch->schid.ssid,
sch->schid.sch_no, cdev->private->imask);
@@ -317,7 +317,7 @@ static int __ccw_device_do_nop(struct ccw_device *cdev)
return ret;
}
/* nop command failed on this path. */
- CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel "
+ CIO_MSG_EVENT(3, "NOP - Device %04x on Subchannel "
"0.%x.%04x, lpm %02X, became 'not operational'\n",
cdev->private->dev_id.devno, sch->schid.ssid,
sch->schid.sch_no, cdev->private->imask);
@@ -362,7 +362,7 @@ __ccw_device_check_pgid(struct ccw_device *cdev)
return -EAGAIN;
}
if (irb->scsw.cc == 3) {
- CIO_MSG_EVENT(2, "SPID - Device %04x on Subchannel 0.%x.%04x,"
+ CIO_MSG_EVENT(3, "SPID - Device %04x on Subchannel 0.%x.%04x,"
" lpm %02X, became 'not operational'\n",
cdev->private->dev_id.devno, sch->schid.ssid,
sch->schid.sch_no, cdev->private->imask);
@@ -391,7 +391,7 @@ static int __ccw_device_check_nop(struct ccw_device *cdev)
return -ETIME;
}
if (irb->scsw.cc == 3) {
- CIO_MSG_EVENT(2, "NOP - Device %04x on Subchannel 0.%x.%04x,"
+ CIO_MSG_EVENT(3, "NOP - Device %04x on Subchannel 0.%x.%04x,"
" lpm %02X, became 'not operational'\n",
cdev->private->dev_id.devno, sch->schid.ssid,
sch->schid.sch_no, cdev->private->imask);
diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c
index 4d4b54277c4..5080f343ad7 100644
--- a/drivers/s390/s390mach.c
+++ b/drivers/s390/s390mach.c
@@ -48,10 +48,11 @@ s390_collect_crw_info(void *param)
int ccode;
struct semaphore *sem;
unsigned int chain;
+ int ignore;
sem = (struct semaphore *)param;
repeat:
- down_interruptible(sem);
+ ignore = down_interruptible(sem);
chain = 0;
while (1) {
if (unlikely(chain > 1)) {
diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c
index 4fab0c23814..b87037ec980 100644
--- a/drivers/sbus/char/bpp.c
+++ b/drivers/sbus/char/bpp.c
@@ -41,7 +41,7 @@
#define BPP_DELAY 100
static const unsigned BPP_MAJOR = LP_MAJOR;
-static const char* dev_name = "bpp";
+static const char *bpp_dev_name = "bpp";
/* When switching from compatibility to a mode where I can read, try
the following mode first. */
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index 0fb5bf4c43a..8508816f303 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -1967,45 +1967,6 @@ cleanup:
return rcode;
}
-
-/*
- * This routine returns information about the system. This does not effect
- * any logic and if the info is wrong - it doesn't matter.
- */
-
-/* Get all the info we can not get from kernel services */
-static int adpt_system_info(void __user *buffer)
-{
- sysInfo_S si;
-
- memset(&si, 0, sizeof(si));
-
- si.osType = OS_LINUX;
- si.osMajorVersion = 0;
- si.osMinorVersion = 0;
- si.osRevision = 0;
- si.busType = SI_PCI_BUS;
- si.processorFamily = DPTI_sig.dsProcessorFamily;
-
-#if defined __i386__
- adpt_i386_info(&si);
-#elif defined (__ia64__)
- adpt_ia64_info(&si);
-#elif defined(__sparc__)
- adpt_sparc_info(&si);
-#elif defined (__alpha__)
- adpt_alpha_info(&si);
-#else
- si.processorType = 0xff ;
-#endif
- if(copy_to_user(buffer, &si, sizeof(si))){
- printk(KERN_WARNING"dpti: Could not copy buffer TO user\n");
- return -EFAULT;
- }
-
- return 0;
-}
-
#if defined __ia64__
static void adpt_ia64_info(sysInfo_S* si)
{
@@ -2016,7 +1977,6 @@ static void adpt_ia64_info(sysInfo_S* si)
}
#endif
-
#if defined __sparc__
static void adpt_sparc_info(sysInfo_S* si)
{
@@ -2026,7 +1986,6 @@ static void adpt_sparc_info(sysInfo_S* si)
si->processorType = PROC_ULTRASPARC;
}
#endif
-
#if defined __alpha__
static void adpt_alpha_info(sysInfo_S* si)
{
@@ -2038,7 +1997,6 @@ static void adpt_alpha_info(sysInfo_S* si)
#endif
#if defined __i386__
-
static void adpt_i386_info(sysInfo_S* si)
{
// This is all the info we need for now
@@ -2059,9 +2017,45 @@ static void adpt_i386_info(sysInfo_S* si)
break;
}
}
+#endif
+
+/*
+ * This routine returns information about the system. This does not effect
+ * any logic and if the info is wrong - it doesn't matter.
+ */
+/* Get all the info we can not get from kernel services */
+static int adpt_system_info(void __user *buffer)
+{
+ sysInfo_S si;
+
+ memset(&si, 0, sizeof(si));
+
+ si.osType = OS_LINUX;
+ si.osMajorVersion = 0;
+ si.osMinorVersion = 0;
+ si.osRevision = 0;
+ si.busType = SI_PCI_BUS;
+ si.processorFamily = DPTI_sig.dsProcessorFamily;
+
+#if defined __i386__
+ adpt_i386_info(&si);
+#elif defined (__ia64__)
+ adpt_ia64_info(&si);
+#elif defined(__sparc__)
+ adpt_sparc_info(&si);
+#elif defined (__alpha__)
+ adpt_alpha_info(&si);
+#else
+ si.processorType = 0xff ;
#endif
+ if (copy_to_user(buffer, &si, sizeof(si))){
+ printk(KERN_WARNING"dpti: Could not copy buffer TO user\n");
+ return -EFAULT;
+ }
+ return 0;
+}
static int adpt_ioctl(struct inode *inode, struct file *file, uint cmd,
ulong arg)
diff --git a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h
index 924cd5a5167..337746d4604 100644
--- a/drivers/scsi/dpti.h
+++ b/drivers/scsi/dpti.h
@@ -316,19 +316,6 @@ static int adpt_close(struct inode *inode, struct file *file);
static void adpt_delay(int millisec);
#endif
-#if defined __ia64__
-static void adpt_ia64_info(sysInfo_S* si);
-#endif
-#if defined __sparc__
-static void adpt_sparc_info(sysInfo_S* si);
-#endif
-#if defined __alpha__
-static void adpt_sparc_info(sysInfo_S* si);
-#endif
-#if defined __i386__
-static void adpt_i386_info(sysInfo_S* si);
-#endif
-
#define PRINT_BUFFER_SIZE 512
#define HBA_FLAGS_DBG_FLAGS_MASK 0xffff0000 // Mask for debug flags
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 1e2b9d826f6..eab03273379 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -556,7 +556,7 @@ static int uart_chars_in_buffer(struct tty_struct *tty)
static void uart_flush_buffer(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
- struct uart_port *port = state->port;
+ struct uart_port *port;
unsigned long flags;
/*
@@ -568,6 +568,7 @@ static void uart_flush_buffer(struct tty_struct *tty)
return;
}
+ port = state->port;
pr_debug("uart_flush_buffer(%d) called\n", tty->index);
spin_lock_irqsave(&port->lock, flags);
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 33b467a8352..1ef6df395e0 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -129,7 +129,7 @@ config USB_ISP1760_PCI
config USB_ISP1760_OF
bool "Support for the OF platform bus"
- depends on USB_ISP1760_HCD && OF
+ depends on USB_ISP1760_HCD && PPC_OF
---help---
Enables support for the device present on the PowerPC
OpenFirmware platform bus.
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index 8a217648b25..a01e987c7d3 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -643,7 +643,7 @@ static void read_buf_callback(struct urb *urb)
static int iuu_bulk_write(struct usb_serial_port *port)
{
struct iuu_private *priv = usb_get_serial_port_data(port);
- unsigned int flags;
+ unsigned long flags;
int result;
int i;
char *buf_ptr = port->write_urb->transfer_buffer;
@@ -694,7 +694,7 @@ static void iuu_uart_read_callback(struct urb *urb)
{
struct usb_serial_port *port = urb->context;
struct iuu_private *priv = usb_get_serial_port_data(port);
- unsigned int flags;
+ unsigned long flags;
int status;
int error = 0;
int len = 0;
@@ -759,7 +759,7 @@ static int iuu_uart_write(struct usb_serial_port *port, const u8 *buf,
int count)
{
struct iuu_private *priv = usb_get_serial_port_data(port);
- unsigned int flags;
+ unsigned long flags;
dbg("%s - enter", __func__);
if (count > 256)
diff --git a/drivers/video/bw2.c b/drivers/video/bw2.c
index 275d9dab0c6..79f85dc402d 100644
--- a/drivers/video/bw2.c
+++ b/drivers/video/bw2.c
@@ -329,7 +329,7 @@ static int __devinit bw2_probe(struct of_device *op, const struct of_device_id *
if (!info->screen_base)
goto out_unmap_regs;
- bw2_blank(0, info);
+ bw2_blank(FB_BLANK_UNBLANK, info);
bw2_init_fix(info, linebytes);
diff --git a/drivers/video/cg3.c b/drivers/video/cg3.c
index 010ea53978f..e31e26a6bb7 100644
--- a/drivers/video/cg3.c
+++ b/drivers/video/cg3.c
@@ -398,7 +398,7 @@ static int __devinit cg3_probe(struct of_device *op,
if (!info->screen_base)
goto out_unmap_regs;
- cg3_blank(0, info);
+ cg3_blank(FB_BLANK_UNBLANK, info);
if (!of_find_property(dp, "width", NULL)) {
err = cg3_do_default_mode(par);
diff --git a/drivers/video/cg6.c b/drivers/video/cg6.c
index fc90db6da65..8000bccecdc 100644
--- a/drivers/video/cg6.c
+++ b/drivers/video/cg6.c
@@ -767,7 +767,7 @@ static int __devinit cg6_probe(struct of_device *op,
cg6_bt_init(par);
cg6_chip_init(info);
- cg6_blank(0, info);
+ cg6_blank(FB_BLANK_UNBLANK, info);
if (fb_alloc_cmap(&info->cmap, 256, 0))
goto out_unmap_regs;
diff --git a/drivers/video/ffb.c b/drivers/video/ffb.c
index 93dca3e2aa5..0f42a696d17 100644
--- a/drivers/video/ffb.c
+++ b/drivers/video/ffb.c
@@ -987,7 +987,7 @@ static int __devinit ffb_probe(struct of_device *op,
* chosen console, it will have video outputs off in
* the DAC.
*/
- ffb_blank(0, info);
+ ffb_blank(FB_BLANK_UNBLANK, info);
if (fb_alloc_cmap(&info->cmap, 256, 0))
goto out_unmap_dac;
diff --git a/drivers/video/leo.c b/drivers/video/leo.c
index f3160fc2979..fb129928d5d 100644
--- a/drivers/video/leo.c
+++ b/drivers/video/leo.c
@@ -601,7 +601,7 @@ static int __devinit leo_probe(struct of_device *op, const struct of_device_id *
leo_init_wids(info);
leo_init_hw(info);
- leo_blank(0, info);
+ leo_blank(FB_BLANK_UNBLANK, info);
if (fb_alloc_cmap(&info->cmap, 256, 0))
goto out_unmap_regs;
diff --git a/drivers/video/p9100.c b/drivers/video/p9100.c
index c95874fe907..676ffb06d1c 100644
--- a/drivers/video/p9100.c
+++ b/drivers/video/p9100.c
@@ -295,7 +295,7 @@ static int __devinit p9100_probe(struct of_device *op, const struct of_device_id
if (!info->screen_base)
goto out_unmap_regs;
- p9100_blank(0, info);
+ p9100_blank(FB_BLANK_UNBLANK, info);
if (fb_alloc_cmap(&info->cmap, 256, 0))
goto out_unmap_screen;
diff --git a/drivers/video/tcx.c b/drivers/video/tcx.c
index a7177430577..44e8c27ed0f 100644
--- a/drivers/video/tcx.c
+++ b/drivers/video/tcx.c
@@ -84,7 +84,7 @@ struct tcx_tec {
struct tcx_thc {
u32 thc_rev;
- u32 thc_pad0[511];
+ u32 thc_pad0[511];
u32 thc_hs; /* hsync timing */
u32 thc_hsdvs;
u32 thc_hd;
@@ -126,10 +126,10 @@ struct tcx_par {
};
/* Reset control plane so that WID is 8-bit plane. */
-static void __tcx_set_control_plane (struct tcx_par *par)
+static void __tcx_set_control_plane(struct tcx_par *par)
{
u32 __iomem *p, *pend;
-
+
if (par->lowdepth)
return;
@@ -143,8 +143,8 @@ static void __tcx_set_control_plane (struct tcx_par *par)
sbus_writel(tmp, p);
}
}
-
-static void tcx_reset (struct fb_info *info)
+
+static void tcx_reset(struct fb_info *info)
{
struct tcx_par *par = (struct tcx_par *) info->par;
unsigned long flags;
@@ -365,7 +365,8 @@ static void tcx_unmap_regs(struct of_device *op, struct fb_info *info,
info->screen_base, par->fbsize);
}
-static int __devinit tcx_init_one(struct of_device *op)
+static int __devinit tcx_probe(struct of_device *op,
+ const struct of_device_id *match)
{
struct device_node *dp = op->node;
struct fb_info *info;
@@ -488,13 +489,6 @@ out_err:
return err;
}
-static int __devinit tcx_probe(struct of_device *dev, const struct of_device_id *match)
-{
- struct of_device *op = to_of_device(&dev->dev);
-
- return tcx_init_one(op);
-}
-
static int __devexit tcx_remove(struct of_device *op)
{
struct fb_info *info = dev_get_drvdata(&op->dev);
diff --git a/fs/affs/affs.h b/fs/affs/affs.h
index d5bd497ab9c..223b1917093 100644
--- a/fs/affs/affs.h
+++ b/fs/affs/affs.h
@@ -48,7 +48,7 @@ struct affs_ext_key {
* affs fs inode data in memory
*/
struct affs_inode_info {
- u32 i_opencnt;
+ atomic_t i_opencnt;
struct semaphore i_link_lock; /* Protects internal inode access. */
struct semaphore i_ext_lock; /* Protects internal inode access. */
#define i_hash_lock i_ext_lock
@@ -170,8 +170,6 @@ extern int affs_rename(struct inode *old_dir, struct dentry *old_dentry,
extern unsigned long affs_parent_ino(struct inode *dir);
extern struct inode *affs_new_inode(struct inode *dir);
extern int affs_notify_change(struct dentry *dentry, struct iattr *attr);
-extern void affs_put_inode(struct inode *inode);
-extern void affs_drop_inode(struct inode *inode);
extern void affs_delete_inode(struct inode *inode);
extern void affs_clear_inode(struct inode *inode);
extern struct inode *affs_iget(struct super_block *sb,
diff --git a/fs/affs/file.c b/fs/affs/file.c
index 1a4f092f24e..6eac7bdeec9 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -48,8 +48,9 @@ affs_file_open(struct inode *inode, struct file *filp)
{
if (atomic_read(&filp->f_count) != 1)
return 0;
- pr_debug("AFFS: open(%d)\n", AFFS_I(inode)->i_opencnt);
- AFFS_I(inode)->i_opencnt++;
+ pr_debug("AFFS: open(%lu,%d)\n",
+ inode->i_ino, atomic_read(&AFFS_I(inode)->i_opencnt));
+ atomic_inc(&AFFS_I(inode)->i_opencnt);
return 0;
}
@@ -58,10 +59,16 @@ affs_file_release(struct inode *inode, struct file *filp)
{
if (atomic_read(&filp->f_count) != 0)
return 0;
- pr_debug("AFFS: release(%d)\n", AFFS_I(inode)->i_opencnt);
- AFFS_I(inode)->i_opencnt--;
- if (!AFFS_I(inode)->i_opencnt)
+ pr_debug("AFFS: release(%lu, %d)\n",
+ inode->i_ino, atomic_read(&AFFS_I(inode)->i_opencnt));
+
+ if (atomic_dec_and_test(&AFFS_I(inode)->i_opencnt)) {
+ mutex_lock(&inode->i_mutex);
+ if (inode->i_size != AFFS_I(inode)->mmu_private)
+ affs_truncate(inode);
affs_free_prealloc(inode);
+ mutex_unlock(&inode->i_mutex);
+ }
return 0;
}
@@ -180,7 +187,7 @@ affs_get_extblock(struct inode *inode, u32 ext)
/* inline the simplest case: same extended block as last time */
struct buffer_head *bh = AFFS_I(inode)->i_ext_bh;
if (ext == AFFS_I(inode)->i_ext_last)
- atomic_inc(&bh->b_count);
+ get_bh(bh);
else
/* we have to do more (not inlined) */
bh = affs_get_extblock_slow(inode, ext);
@@ -306,7 +313,7 @@ store_ext:
affs_brelse(AFFS_I(inode)->i_ext_bh);
AFFS_I(inode)->i_ext_last = ext;
AFFS_I(inode)->i_ext_bh = bh;
- atomic_inc(&bh->b_count);
+ get_bh(bh);
return bh;
@@ -324,7 +331,6 @@ affs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_resul
pr_debug("AFFS: get_block(%u, %lu)\n", (u32)inode->i_ino, (unsigned long)block);
-
BUG_ON(block > (sector_t)0x7fffffffUL);
if (block >= AFFS_I(inode)->i_blkcnt) {
@@ -827,6 +833,8 @@ affs_truncate(struct inode *inode)
res = mapping->a_ops->write_begin(NULL, mapping, size, 0, 0, &page, &fsdata);
if (!res)
res = mapping->a_ops->write_end(NULL, mapping, size, 0, 0, page, fsdata);
+ else
+ inode->i_size = AFFS_I(inode)->mmu_private;
mark_inode_dirty(inode);
return;
} else if (inode->i_size == AFFS_I(inode)->mmu_private)
@@ -862,6 +870,7 @@ affs_truncate(struct inode *inode)
blk++;
} else
AFFS_HEAD(ext_bh)->first_data = 0;
+ AFFS_HEAD(ext_bh)->block_count = cpu_to_be32(i);
size = AFFS_SB(sb)->s_hashsize;
if (size > blkcnt - blk + i)
size = blkcnt - blk + i;
diff --git a/fs/affs/inode.c b/fs/affs/inode.c
index 27fe6cbe43a..a13b334a391 100644
--- a/fs/affs/inode.c
+++ b/fs/affs/inode.c
@@ -58,7 +58,7 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino)
AFFS_I(inode)->i_extcnt = 1;
AFFS_I(inode)->i_ext_last = ~1;
AFFS_I(inode)->i_protect = prot;
- AFFS_I(inode)->i_opencnt = 0;
+ atomic_set(&AFFS_I(inode)->i_opencnt, 0);
AFFS_I(inode)->i_blkcnt = 0;
AFFS_I(inode)->i_lc = NULL;
AFFS_I(inode)->i_lc_size = 0;
@@ -108,8 +108,6 @@ struct inode *affs_iget(struct super_block *sb, unsigned long ino)
inode->i_mode |= S_IFDIR;
} else
inode->i_mode = S_IRUGO | S_IXUGO | S_IWUSR | S_IFDIR;
- if (tail->link_chain)
- inode->i_nlink = 2;
/* Maybe it should be controlled by mount parameter? */
//inode->i_mode |= S_ISVTX;
inode->i_op = &affs_dir_inode_operations;
@@ -245,31 +243,12 @@ out:
}
void
-affs_put_inode(struct inode *inode)
-{
- pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
- affs_free_prealloc(inode);
-}
-
-void
-affs_drop_inode(struct inode *inode)
-{
- mutex_lock(&inode->i_mutex);
- if (inode->i_size != AFFS_I(inode)->mmu_private)
- affs_truncate(inode);
- mutex_unlock(&inode->i_mutex);
-
- generic_drop_inode(inode);
-}
-
-void
affs_delete_inode(struct inode *inode)
{
pr_debug("AFFS: delete_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
truncate_inode_pages(&inode->i_data, 0);
inode->i_size = 0;
- if (S_ISREG(inode->i_mode))
- affs_truncate(inode);
+ affs_truncate(inode);
clear_inode(inode);
affs_free_block(inode->i_sb, inode->i_ino);
}
@@ -277,9 +256,12 @@ affs_delete_inode(struct inode *inode)
void
affs_clear_inode(struct inode *inode)
{
- unsigned long cache_page = (unsigned long) AFFS_I(inode)->i_lc;
+ unsigned long cache_page;
pr_debug("AFFS: clear_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink);
+
+ affs_free_prealloc(inode);
+ cache_page = (unsigned long)AFFS_I(inode)->i_lc;
if (cache_page) {
pr_debug("AFFS: freeing ext cache\n");
AFFS_I(inode)->i_lc = NULL;
@@ -316,7 +298,7 @@ affs_new_inode(struct inode *dir)
inode->i_ino = block;
inode->i_nlink = 1;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
- AFFS_I(inode)->i_opencnt = 0;
+ atomic_set(&AFFS_I(inode)->i_opencnt, 0);
AFFS_I(inode)->i_blkcnt = 0;
AFFS_I(inode)->i_lc = NULL;
AFFS_I(inode)->i_lc_size = 0;
@@ -369,12 +351,12 @@ affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s3
switch (type) {
case ST_LINKFILE:
case ST_LINKDIR:
- inode_bh = bh;
retval = -ENOSPC;
block = affs_alloc_block(dir, dir->i_ino);
if (!block)
goto err;
retval = -EIO;
+ inode_bh = bh;
bh = affs_getzeroblk(sb, block);
if (!bh)
goto err;
diff --git a/fs/affs/namei.c b/fs/affs/namei.c
index 2218f1ee71c..cfcf1b6cf82 100644
--- a/fs/affs/namei.c
+++ b/fs/affs/namei.c
@@ -234,7 +234,8 @@ affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
int
affs_unlink(struct inode *dir, struct dentry *dentry)
{
- pr_debug("AFFS: unlink(dir=%d, \"%.*s\")\n", (u32)dir->i_ino,
+ pr_debug("AFFS: unlink(dir=%d, %lu \"%.*s\")\n", (u32)dir->i_ino,
+ dentry->d_inode->i_ino,
(int)dentry->d_name.len, dentry->d_name.name);
return affs_remove_header(dentry);
@@ -302,7 +303,8 @@ affs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
int
affs_rmdir(struct inode *dir, struct dentry *dentry)
{
- pr_debug("AFFS: rmdir(dir=%u, \"%.*s\")\n", (u32)dir->i_ino,
+ pr_debug("AFFS: rmdir(dir=%u, %lu \"%.*s\")\n", (u32)dir->i_ino,
+ dentry->d_inode->i_ino,
(int)dentry->d_name.len, dentry->d_name.name);
return affs_remove_header(dentry);
diff --git a/fs/affs/super.c b/fs/affs/super.c
index 01d25d53254..d214837d5e4 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -71,12 +71,18 @@ static struct kmem_cache * affs_inode_cachep;
static struct inode *affs_alloc_inode(struct super_block *sb)
{
- struct affs_inode_info *ei;
- ei = (struct affs_inode_info *)kmem_cache_alloc(affs_inode_cachep, GFP_KERNEL);
- if (!ei)
+ struct affs_inode_info *i;
+
+ i = kmem_cache_alloc(affs_inode_cachep, GFP_KERNEL);
+ if (!i)
return NULL;
- ei->vfs_inode.i_version = 1;
- return &ei->vfs_inode;
+
+ i->vfs_inode.i_version = 1;
+ i->i_lc = NULL;
+ i->i_ext_bh = NULL;
+ i->i_pa_cnt = 0;
+
+ return &i->vfs_inode;
}
static void affs_destroy_inode(struct inode *inode)
@@ -114,8 +120,6 @@ static const struct super_operations affs_sops = {
.alloc_inode = affs_alloc_inode,
.destroy_inode = affs_destroy_inode,
.write_inode = affs_write_inode,
- .put_inode = affs_put_inode,
- .drop_inode = affs_drop_inode,
.delete_inode = affs_delete_inode,
.clear_inode = affs_clear_inode,
.put_super = affs_put_super,
diff --git a/fs/bio.c b/fs/bio.c
index 799f86deff2..78562574cb5 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -158,7 +158,7 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
bio_init(bio);
if (likely(nr_iovecs)) {
- unsigned long idx = 0; /* shut up gcc */
+ unsigned long uninitialized_var(idx);
bvl = bvec_alloc_bs(gfp_mask, nr_iovecs, &idx, bs);
if (unlikely(!bvl)) {
@@ -963,6 +963,7 @@ static void bio_copy_kern_endio(struct bio *bio, int err)
* @data: pointer to buffer to copy
* @len: length in bytes
* @gfp_mask: allocation flags for bio and page allocation
+ * @reading: data direction is READ
*
* copy the kernel address into a bio suitable for io to a block
* device. Returns an error pointer in case of error.
diff --git a/fs/inode.c b/fs/inode.c
index bf647813042..c36d9480335 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -1149,13 +1149,8 @@ static inline void iput_final(struct inode *inode)
void iput(struct inode *inode)
{
if (inode) {
- const struct super_operations *op = inode->i_sb->s_op;
-
BUG_ON(inode->i_state == I_CLEAR);
- if (op && op->put_inode)
- op->put_inode(inode);
-
if (atomic_dec_and_lock(&inode->i_count, &inode_lock))
iput_final(inode);
}
diff --git a/fs/locks.c b/fs/locks.c
index 663c069b59b..0ac6b92cb0b 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -1753,6 +1753,7 @@ int fcntl_setlk(unsigned int fd, struct file *filp, unsigned int cmd,
struct file_lock *file_lock = locks_alloc_lock();
struct flock flock;
struct inode *inode;
+ struct file *f;
int error;
if (file_lock == NULL)
@@ -1825,7 +1826,15 @@ again:
* Attempt to detect a close/fcntl race and recover by
* releasing the lock that was just acquired.
*/
- if (!error && fcheck(fd) != filp && flock.l_type != F_UNLCK) {
+ /*
+ * we need that spin_lock here - it prevents reordering between
+ * update of inode->i_flock and check for it done in close().
+ * rcu_read_lock() wouldn't do.
+ */
+ spin_lock(&current->files->file_lock);
+ f = fcheck(fd);
+ spin_unlock(&current->files->file_lock);
+ if (!error && f != filp && flock.l_type != F_UNLCK) {
flock.l_type = F_UNLCK;
goto again;
}
@@ -1881,6 +1890,7 @@ int fcntl_setlk64(unsigned int fd, struct file *filp, unsigned int cmd,
struct file_lock *file_lock = locks_alloc_lock();
struct flock64 flock;
struct inode *inode;
+ struct file *f;
int error;
if (file_lock == NULL)
@@ -1953,7 +1963,10 @@ again:
* Attempt to detect a close/fcntl race and recover by
* releasing the lock that was just acquired.
*/
- if (!error && fcheck(fd) != filp && flock.l_type != F_UNLCK) {
+ spin_lock(&current->files->file_lock);
+ f = fcheck(fd);
+ spin_unlock(&current->files->file_lock);
+ if (!error && f != filp && flock.l_type != F_UNLCK) {
flock.l_type = F_UNLCK;
goto again;
}
diff --git a/fs/pipe.c b/fs/pipe.c
index 3499f9ff631..ec228bc9f88 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -17,6 +17,7 @@
#include <linux/highmem.h>
#include <linux/pagemap.h>
#include <linux/audit.h>
+#include <linux/syscalls.h>
#include <asm/uaccess.h>
#include <asm/ioctls.h>
@@ -1086,8 +1087,11 @@ asmlinkage long __weak sys_pipe(int __user *fildes)
error = do_pipe(fd);
if (!error) {
- if (copy_to_user(fildes, fd, sizeof(fd)))
+ if (copy_to_user(fildes, fd, sizeof(fd))) {
+ sys_close(fd[0]);
+ sys_close(fd[1]);
error = -EFAULT;
+ }
}
return error;
}
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index e2b8e769f51..88717c0f941 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -5,11 +5,9 @@
#include <linux/highmem.h>
#include <linux/ptrace.h>
#include <linux/pagemap.h>
-#include <linux/ptrace.h>
#include <linux/mempolicy.h>
#include <linux/swap.h>
#include <linux/swapops.h>
-#include <linux/seq_file.h>
#include <asm/elf.h>
#include <asm/uaccess.h>
diff --git a/fs/splice.c b/fs/splice.c
index 633f58ebfb7..78150038b58 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -811,24 +811,19 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
{
struct address_space *mapping = out->f_mapping;
struct inode *inode = mapping->host;
- int killsuid, killpriv;
+ struct splice_desc sd = {
+ .total_len = len,
+ .flags = flags,
+ .pos = *ppos,
+ .u.file = out,
+ };
ssize_t ret;
- int err = 0;
-
- killpriv = security_inode_need_killpriv(out->f_path.dentry);
- killsuid = should_remove_suid(out->f_path.dentry);
- if (unlikely(killsuid || killpriv)) {
- mutex_lock(&inode->i_mutex);
- if (killpriv)
- err = security_inode_killpriv(out->f_path.dentry);
- if (!err && killsuid)
- err = __remove_suid(out->f_path.dentry, killsuid);
- mutex_unlock(&inode->i_mutex);
- if (err)
- return err;
- }
- ret = splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_file);
+ inode_double_lock(inode, pipe->inode);
+ ret = remove_suid(out->f_path.dentry);
+ if (likely(!ret))
+ ret = __splice_from_pipe(pipe, &sd, pipe_to_file);
+ inode_double_unlock(inode, pipe->inode);
if (ret > 0) {
unsigned long nr_pages;
@@ -840,6 +835,8 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out,
* sync it.
*/
if (unlikely((out->f_flags & O_SYNC) || IS_SYNC(inode))) {
+ int err;
+
mutex_lock(&inode->i_mutex);
err = generic_osync_inode(inode, mapping,
OSYNC_METADATA|OSYNC_DATA);
@@ -1075,7 +1072,7 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
ret = splice_direct_to_actor(in, &sd, direct_splice_actor);
if (ret > 0)
- *ppos = sd.pos;
+ *ppos += ret;
return ret;
}
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index 2b34c8ca6c8..d3231947db1 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -32,6 +32,7 @@
#include <linux/buffer_head.h>
#include <linux/sched.h>
#include <linux/crc-itu-t.h>
+#include <linux/exportfs.h>
static inline int udf_match(int len1, const char *name1, int len2,
const char *name2)
@@ -158,6 +159,8 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
sector_t offset;
struct extent_position epos = {};
struct udf_inode_info *dinfo = UDF_I(dir);
+ int isdotdot = dentry->d_name.len == 2 &&
+ dentry->d_name.name[0] == '.' && dentry->d_name.name[1] == '.';
size = udf_ext0_offset(dir) + dir->i_size;
f_pos = udf_ext0_offset(dir);
@@ -225,6 +228,12 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir,
continue;
}
+ if ((cfi->fileCharacteristics & FID_FILE_CHAR_PARENT) &&
+ isdotdot) {
+ brelse(epos.bh);
+ return fi;
+ }
+
if (!lfi)
continue;
@@ -286,9 +295,8 @@ static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,
}
}
unlock_kernel();
- d_add(dentry, inode);
- return NULL;
+ return d_splice_alias(inode, dentry);
}
static struct fileIdentDesc *udf_add_entry(struct inode *dir,
@@ -307,7 +315,7 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
uint16_t liu;
int block;
kernel_lb_addr eloc;
- uint32_t elen;
+ uint32_t elen = 0;
sector_t offset;
struct extent_position epos = {};
struct udf_inode_info *dinfo;
@@ -398,7 +406,8 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
}
add:
- if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
+ /* Is there any extent whose size we need to round up? */
+ if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB && elen) {
elen = (elen + sb->s_blocksize - 1) & ~(sb->s_blocksize - 1);
if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
epos.offset -= sizeof(short_ad);
@@ -1232,6 +1241,134 @@ end_rename:
return retval;
}
+static struct dentry *udf_get_parent(struct dentry *child)
+{
+ struct dentry *parent;
+ struct inode *inode = NULL;
+ struct dentry dotdot;
+ struct fileIdentDesc cfi;
+ struct udf_fileident_bh fibh;
+
+ dotdot.d_name.name = "..";
+ dotdot.d_name.len = 2;
+
+ lock_kernel();
+ if (!udf_find_entry(child->d_inode, &dotdot, &fibh, &cfi))
+ goto out_unlock;
+
+ if (fibh.sbh != fibh.ebh)
+ brelse(fibh.ebh);
+ brelse(fibh.sbh);
+
+ inode = udf_iget(child->d_inode->i_sb,
+ lelb_to_cpu(cfi.icb.extLocation));
+ if (!inode)
+ goto out_unlock;
+ unlock_kernel();
+
+ parent = d_alloc_anon(inode);
+ if (!parent) {
+ iput(inode);
+ parent = ERR_PTR(-ENOMEM);
+ }
+
+ return parent;
+out_unlock:
+ unlock_kernel();
+ return ERR_PTR(-EACCES);
+}
+
+
+static struct dentry *udf_nfs_get_inode(struct super_block *sb, u32 block,
+ u16 partref, __u32 generation)
+{
+ struct inode *inode;
+ struct dentry *result;
+ kernel_lb_addr loc;
+
+ if (block == 0)
+ return ERR_PTR(-ESTALE);
+
+ loc.logicalBlockNum = block;
+ loc.partitionReferenceNum = partref;
+ inode = udf_iget(sb, loc);
+
+ if (inode == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ if (generation && inode->i_generation != generation) {
+ iput(inode);
+ return ERR_PTR(-ESTALE);
+ }
+ result = d_alloc_anon(inode);
+ if (!result) {
+ iput(inode);
+ return ERR_PTR(-ENOMEM);
+ }
+ return result;
+}
+
+static struct dentry *udf_fh_to_dentry(struct super_block *sb,
+ struct fid *fid, int fh_len, int fh_type)
+{
+ if ((fh_len != 3 && fh_len != 5) ||
+ (fh_type != FILEID_UDF_WITH_PARENT &&
+ fh_type != FILEID_UDF_WITHOUT_PARENT))
+ return NULL;
+
+ return udf_nfs_get_inode(sb, fid->udf.block, fid->udf.partref,
+ fid->udf.generation);
+}
+
+static struct dentry *udf_fh_to_parent(struct super_block *sb,
+ struct fid *fid, int fh_len, int fh_type)
+{
+ if (fh_len != 5 || fh_type != FILEID_UDF_WITH_PARENT)
+ return NULL;
+
+ return udf_nfs_get_inode(sb, fid->udf.parent_block,
+ fid->udf.parent_partref,
+ fid->udf.parent_generation);
+}
+static int udf_encode_fh(struct dentry *de, __u32 *fh, int *lenp,
+ int connectable)
+{
+ int len = *lenp;
+ struct inode *inode = de->d_inode;
+ kernel_lb_addr location = UDF_I(inode)->i_location;
+ struct fid *fid = (struct fid *)fh;
+ int type = FILEID_UDF_WITHOUT_PARENT;
+
+ if (len < 3 || (connectable && len < 5))
+ return 255;
+
+ *lenp = 3;
+ fid->udf.block = location.logicalBlockNum;
+ fid->udf.partref = location.partitionReferenceNum;
+ fid->udf.generation = inode->i_generation;
+
+ if (connectable && !S_ISDIR(inode->i_mode)) {
+ spin_lock(&de->d_lock);
+ inode = de->d_parent->d_inode;
+ location = UDF_I(inode)->i_location;
+ fid->udf.parent_block = location.logicalBlockNum;
+ fid->udf.parent_partref = location.partitionReferenceNum;
+ fid->udf.parent_generation = inode->i_generation;
+ spin_unlock(&de->d_lock);
+ *lenp = 5;
+ type = FILEID_UDF_WITH_PARENT;
+ }
+
+ return type;
+}
+
+const struct export_operations udf_export_ops = {
+ .encode_fh = udf_encode_fh,
+ .fh_to_dentry = udf_fh_to_dentry,
+ .fh_to_parent = udf_fh_to_parent,
+ .get_parent = udf_get_parent,
+};
+
const struct inode_operations udf_dir_inode_operations = {
.lookup = udf_lookup,
.create = udf_create,
diff --git a/fs/udf/partition.c b/fs/udf/partition.c
index 63610f026ae..96dfd207c3d 100644
--- a/fs/udf/partition.c
+++ b/fs/udf/partition.c
@@ -27,8 +27,8 @@
#include <linux/slab.h>
#include <linux/buffer_head.h>
-inline uint32_t udf_get_pblock(struct super_block *sb, uint32_t block,
- uint16_t partition, uint32_t offset)
+uint32_t udf_get_pblock(struct super_block *sb, uint32_t block,
+ uint16_t partition, uint32_t offset)
{
struct udf_sb_info *sbi = UDF_SB(sb);
struct udf_part_map *map;
diff --git a/fs/udf/super.c b/fs/udf/super.c
index 9fb18a340fc..7a5f69be6ac 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -1933,6 +1933,7 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
/* Fill in the rest of the superblock */
sb->s_op = &udf_sb_ops;
+ sb->s_export_op = &udf_export_ops;
sb->dq_op = NULL;
sb->s_dirt = 0;
sb->s_magic = UDF_SUPER_MAGIC;
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
index f3f45d02927..8fa9c2d7091 100644
--- a/fs/udf/udfdecl.h
+++ b/fs/udf/udfdecl.h
@@ -73,6 +73,7 @@ struct task_struct;
struct buffer_head;
struct super_block;
+extern const struct export_operations udf_export_ops;
extern const struct inode_operations udf_dir_inode_operations;
extern const struct file_operations udf_dir_operations;
extern const struct inode_operations udf_file_inode_operations;
diff --git a/include/asm-mn10300/processor.h b/include/asm-mn10300/processor.h
index f1b081f5346..73239271873 100644
--- a/include/asm-mn10300/processor.h
+++ b/include/asm-mn10300/processor.h
@@ -58,7 +58,7 @@ extern struct mn10300_cpuinfo boot_cpu_data;
extern void identify_cpu(struct mn10300_cpuinfo *);
extern void print_cpu_info(struct mn10300_cpuinfo *);
extern void dodgy_tsc(void);
-#define cpu_relax() do {} while (0)
+#define cpu_relax() barrier()
/*
* User space process size: 1.75GB (default).
diff --git a/include/asm-s390/kvm_host.h b/include/asm-s390/kvm_host.h
index f8204a4f2e0..18cbd8a3979 100644
--- a/include/asm-s390/kvm_host.h
+++ b/include/asm-s390/kvm_host.h
@@ -104,6 +104,7 @@ struct sie_block {
struct kvm_vcpu_stat {
u32 exit_userspace;
+ u32 exit_null;
u32 exit_external_request;
u32 exit_external_interrupt;
u32 exit_stop_request;
diff --git a/include/asm-s390/page.h b/include/asm-s390/page.h
index f0f4579eac1..12fd9c4f0f1 100644
--- a/include/asm-s390/page.h
+++ b/include/asm-s390/page.h
@@ -125,6 +125,17 @@ page_get_storage_key(unsigned long addr)
return skey;
}
+#ifdef CONFIG_PAGE_STATES
+
+struct page;
+void arch_free_page(struct page *page, int order);
+void arch_alloc_page(struct page *page, int order);
+
+#define HAVE_ARCH_FREE_PAGE
+#define HAVE_ARCH_ALLOC_PAGE
+
+#endif
+
#endif /* !__ASSEMBLY__ */
/* to align the pointer to the (next) page boundary */
diff --git a/include/asm-s390/ptrace.h b/include/asm-s390/ptrace.h
index 441d7c26085..d7d4e2eb3e6 100644
--- a/include/asm-s390/ptrace.h
+++ b/include/asm-s390/ptrace.h
@@ -471,6 +471,8 @@ struct task_struct;
extern void user_enable_single_step(struct task_struct *);
extern void user_disable_single_step(struct task_struct *);
+#define __ARCH_WANT_COMPAT_SYS_PTRACE
+
#define user_mode(regs) (((regs)->psw.mask & PSW_MASK_PSTATE) != 0)
#define instruction_pointer(regs) ((regs)->psw.addr & PSW_ADDR_INSN)
#define regs_return_value(regs)((regs)->gprs[2])
diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h
index c819ae25a84..e0d4500d5f9 100644
--- a/include/asm-s390/system.h
+++ b/include/asm-s390/system.h
@@ -116,6 +116,12 @@ extern void pfault_fini(void);
#define pfault_fini() do { } while (0)
#endif /* CONFIG_PFAULT */
+#ifdef CONFIG_PAGE_STATES
+extern void cmma_init(void);
+#else
+static inline void cmma_init(void) { }
+#endif
+
#define finish_arch_switch(prev) do { \
set_fs(current->thread.mm_segment); \
account_vtime(prev); \
diff --git a/include/asm-x86/pgtable_32.h b/include/asm-x86/pgtable_32.h
index 577ab79c4c2..d7f0403bbec 100644
--- a/include/asm-x86/pgtable_32.h
+++ b/include/asm-x86/pgtable_32.h
@@ -88,14 +88,7 @@ extern unsigned long pg0[];
/* To avoid harmful races, pmd_none(x) should check only the lower when PAE */
#define pmd_none(x) (!(unsigned long)pmd_val((x)))
#define pmd_present(x) (pmd_val((x)) & _PAGE_PRESENT)
-
-extern int pmd_bad(pmd_t pmd);
-
-#define pmd_bad_v1(x) \
- (_KERNPG_TABLE != (pmd_val((x)) & ~(PAGE_MASK | _PAGE_USER)))
-#define pmd_bad_v2(x) \
- (_KERNPG_TABLE != (pmd_val((x)) & ~(PAGE_MASK | _PAGE_USER | \
- _PAGE_PSE | _PAGE_NX)))
+#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE)
#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT))
diff --git a/include/asm-x86/pgtable_64.h b/include/asm-x86/pgtable_64.h
index a3bbf8766c1..efe83dcbd41 100644
--- a/include/asm-x86/pgtable_64.h
+++ b/include/asm-x86/pgtable_64.h
@@ -158,14 +158,12 @@ static inline unsigned long pgd_bad(pgd_t pgd)
static inline unsigned long pud_bad(pud_t pud)
{
- return pud_val(pud) &
- ~(PTE_MASK | _KERNPG_TABLE | _PAGE_USER | _PAGE_PSE | _PAGE_NX);
+ return pud_val(pud) & ~(PTE_MASK | _KERNPG_TABLE | _PAGE_USER);
}
static inline unsigned long pmd_bad(pmd_t pmd)
{
- return pmd_val(pmd) &
- ~(PTE_MASK | _KERNPG_TABLE | _PAGE_USER | _PAGE_PSE | _PAGE_NX);
+ return pmd_val(pmd) & ~(PTE_MASK | _KERNPG_TABLE | _PAGE_USER);
}
#define pte_none(x) (!pte_val((x)))
diff --git a/include/linux/exportfs.h b/include/linux/exportfs.h
index de8387b7ceb..f5abd130663 100644
--- a/include/linux/exportfs.h
+++ b/include/linux/exportfs.h
@@ -33,6 +33,19 @@ enum fid_type {
* 32 bit parent directory inode number.
*/
FILEID_INO32_GEN_PARENT = 2,
+
+ /*
+ * 32 bit block number, 16 bit partition reference,
+ * 16 bit unused, 32 bit generation number.
+ */
+ FILEID_UDF_WITHOUT_PARENT = 0x51,
+
+ /*
+ * 32 bit block number, 16 bit partition reference,
+ * 16 bit unused, 32 bit generation number,
+ * 32 bit parent block number, 32 bit parent generation number
+ */
+ FILEID_UDF_WITH_PARENT = 0x52,
};
struct fid {
@@ -43,6 +56,14 @@ struct fid {
u32 parent_ino;
u32 parent_gen;
} i32;
+ struct {
+ u32 block;
+ u16 partref;
+ u16 parent_partref;
+ u32 generation;
+ u32 parent_block;
+ u32 parent_generation;
+ } udf;
__u32 raw[0];
};
};
diff --git a/include/linux/fs.h b/include/linux/fs.h
index a1ba005d08e..f413085f748 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1289,17 +1289,12 @@ extern ssize_t vfs_readv(struct file *, const struct iovec __user *,
extern ssize_t vfs_writev(struct file *, const struct iovec __user *,
unsigned long, loff_t *);
-/*
- * NOTE: write_inode, delete_inode, clear_inode, put_inode can be called
- * without the big kernel lock held in all filesystems.
- */
struct super_operations {
struct inode *(*alloc_inode)(struct super_block *sb);
void (*destroy_inode)(struct inode *);
void (*dirty_inode) (struct inode *);
int (*write_inode) (struct inode *, int);
- void (*put_inode) (struct inode *);
void (*drop_inode) (struct inode *);
void (*delete_inode) (struct inode *);
void (*put_super) (struct super_block *);
@@ -1821,7 +1816,6 @@ extern void iget_failed(struct inode *);
extern void clear_inode(struct inode *);
extern void destroy_inode(struct inode *);
extern struct inode *new_inode(struct super_block *);
-extern int __remove_suid(struct dentry *, int);
extern int should_remove_suid(struct dentry *);
extern int remove_suid(struct dentry *);
diff --git a/include/linux/genhd.h b/include/linux/genhd.h
index ecd2bf63fc8..e9874e7fcdf 100644
--- a/include/linux/genhd.h
+++ b/include/linux/genhd.h
@@ -178,17 +178,17 @@ static inline struct hd_struct *get_part(struct gendisk *gendiskp,
static inline void disk_stat_set_all(struct gendisk *gendiskp, int value) {
int i;
+
for_each_possible_cpu(i)
memset(per_cpu_ptr(gendiskp->dkstats, i), value,
- sizeof (struct disk_stats));
+ sizeof(struct disk_stats));
}
#define __part_stat_add(part, field, addnd) \
(per_cpu_ptr(part->dkstats, smp_processor_id())->field += addnd)
-#define __all_stat_add(gendiskp, field, addnd, sector) \
+#define __all_stat_add(gendiskp, part, field, addnd, sector) \
({ \
- struct hd_struct *part = get_part(gendiskp, sector); \
if (part) \
__part_stat_add(part, field, addnd); \
__disk_stat_add(gendiskp, field, addnd); \
@@ -203,11 +203,13 @@ static inline void disk_stat_set_all(struct gendisk *gendiskp, int value) {
res; \
})
-static inline void part_stat_set_all(struct hd_struct *part, int value) {
+static inline void part_stat_set_all(struct hd_struct *part, int value)
+{
int i;
+
for_each_possible_cpu(i)
memset(per_cpu_ptr(part->dkstats, i), value,
- sizeof(struct disk_stats));
+ sizeof(struct disk_stats));
}
#else /* !CONFIG_SMP */
@@ -223,9 +225,8 @@ static inline void disk_stat_set_all(struct gendisk *gendiskp, int value)
#define __part_stat_add(part, field, addnd) \
(part->dkstats.field += addnd)
-#define __all_stat_add(gendiskp, field, addnd, sector) \
+#define __all_stat_add(gendiskp, part, field, addnd, sector) \
({ \
- struct hd_struct *part = get_part(gendiskp, sector); \
if (part) \
part->dkstats.field += addnd; \
__disk_stat_add(gendiskp, field, addnd); \
@@ -276,10 +277,10 @@ static inline void part_stat_set_all(struct hd_struct *part, int value)
#define part_stat_sub(gendiskp, field, subnd) \
part_stat_add(gendiskp, field, -subnd)
-#define all_stat_add(gendiskp, field, addnd, sector) \
+#define all_stat_add(gendiskp, part, field, addnd, sector) \
do { \
preempt_disable(); \
- __all_stat_add(gendiskp, field, addnd, sector); \
+ __all_stat_add(gendiskp, part, field, addnd, sector); \
preempt_enable(); \
} while (0)
@@ -288,15 +289,15 @@ static inline void part_stat_set_all(struct hd_struct *part, int value)
#define all_stat_dec(gendiskp, field, sector) \
all_stat_add(gendiskp, field, -1, sector)
-#define __all_stat_inc(gendiskp, field, sector) \
- __all_stat_add(gendiskp, field, 1, sector)
-#define all_stat_inc(gendiskp, field, sector) \
- all_stat_add(gendiskp, field, 1, sector)
+#define __all_stat_inc(gendiskp, part, field, sector) \
+ __all_stat_add(gendiskp, part, field, 1, sector)
+#define all_stat_inc(gendiskp, part, field, sector) \
+ all_stat_add(gendiskp, part, field, 1, sector)
-#define __all_stat_sub(gendiskp, field, subnd, sector) \
- __all_stat_add(gendiskp, field, -subnd, sector)
-#define all_stat_sub(gendiskp, field, subnd, sector) \
- all_stat_add(gendiskp, field, -subnd, sector)
+#define __all_stat_sub(gendiskp, part, field, subnd, sector) \
+ __all_stat_add(gendiskp, part, field, -subnd, sector)
+#define all_stat_sub(gendiskp, part, field, subnd, sector) \
+ all_stat_add(gendiskp, part, field, -subnd, sector)
/* Inlines to alloc and free disk stats in struct gendisk */
#ifdef CONFIG_SMP
diff --git a/include/linux/ioprio.h b/include/linux/ioprio.h
index 2a3bb1bb743..f98a656b17e 100644
--- a/include/linux/ioprio.h
+++ b/include/linux/ioprio.h
@@ -68,6 +68,20 @@ static inline int task_nice_ioprio(struct task_struct *task)
}
/*
+ * This is for the case where the task hasn't asked for a specific IO class.
+ * Check for idle and rt task process, and return appropriate IO class.
+ */
+static inline int task_nice_ioclass(struct task_struct *task)
+{
+ if (task->policy == SCHED_IDLE)
+ return IOPRIO_CLASS_IDLE;
+ else if (task->policy == SCHED_FIFO || task->policy == SCHED_RR)
+ return IOPRIO_CLASS_RT;
+ else
+ return IOPRIO_CLASS_BE;
+}
+
+/*
* For inheritance, return the highest of the two given priorities
*/
extern int ioprio_best(unsigned short aprio, unsigned short bprio);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index d1dfe872ee3..7e206da1fbf 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -1039,6 +1039,7 @@ extern void ata_eh_thaw_port(struct ata_port *ap);
extern void ata_eh_qc_complete(struct ata_queued_cmd *qc);
extern void ata_eh_qc_retry(struct ata_queued_cmd *qc);
+extern void ata_eh_analyze_ncq_error(struct ata_link *link);
extern void ata_do_eh(struct ata_port *ap, ata_prereset_fn_t prereset,
ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
@@ -1381,6 +1382,21 @@ static inline struct ata_port *ata_shost_to_port(struct Scsi_Host *host)
return *(struct ata_port **)&host->hostdata[0];
}
+static inline int ata_check_ready(u8 status)
+{
+ /* Some controllers report 0x77 or 0x7f during intermediate
+ * not-ready stages.
+ */
+ if (status == 0x77 || status == 0x7f)
+ return 0;
+
+ /* 0xff indicates either no device or device not ready */
+ if (status == 0xff)
+ return -ENODEV;
+
+ return !(status & ATA_BUSY);
+}
+
/**************************************************************************
* PMP - drivers/ata/libata-pmp.c
diff --git a/include/net/ip.h b/include/net/ip.h
index 6d7bcd5e62d..3b40bc2234b 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -210,7 +210,7 @@ int ip_dont_fragment(struct sock *sk, struct dst_entry *dst)
{
return (inet_sk(sk)->pmtudisc == IP_PMTUDISC_DO ||
(inet_sk(sk)->pmtudisc == IP_PMTUDISC_WANT &&
- !(dst_metric(dst, RTAX_LOCK)&(1<<RTAX_MTU))));
+ !(dst_metric_locked(dst, RTAX_MTU))));
}
extern void __ip_select_ident(struct iphdr *iph, struct dst_entry *dst, int more);
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index d1350bcccb0..2933d7474a7 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -648,14 +648,46 @@ extern void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family,
extern void xfrm_audit_state_icvfail(struct xfrm_state *x,
struct sk_buff *skb, u8 proto);
#else
-#define xfrm_audit_policy_add(x, r, a, se, s) do { ; } while (0)
-#define xfrm_audit_policy_delete(x, r, a, se, s) do { ; } while (0)
-#define xfrm_audit_state_add(x, r, a, se, s) do { ; } while (0)
-#define xfrm_audit_state_delete(x, r, a, se, s) do { ; } while (0)
-#define xfrm_audit_state_replay_overflow(x, s) do { ; } while (0)
-#define xfrm_audit_state_notfound_simple(s, f) do { ; } while (0)
-#define xfrm_audit_state_notfound(s, f, sp, sq) do { ; } while (0)
-#define xfrm_audit_state_icvfail(x, s, p) do { ; } while (0)
+
+static inline void xfrm_audit_policy_add(struct xfrm_policy *xp, int result,
+ u32 auid, u32 ses, u32 secid)
+{
+}
+
+static inline void xfrm_audit_policy_delete(struct xfrm_policy *xp, int result,
+ u32 auid, u32 ses, u32 secid)
+{
+}
+
+static inline void xfrm_audit_state_add(struct xfrm_state *x, int result,
+ u32 auid, u32 ses, u32 secid)
+{
+}
+
+static inline void xfrm_audit_state_delete(struct xfrm_state *x, int result,
+ u32 auid, u32 ses, u32 secid)
+{
+}
+
+static inline void xfrm_audit_state_replay_overflow(struct xfrm_state *x,
+ struct sk_buff *skb)
+{
+}
+
+static inline void xfrm_audit_state_notfound_simple(struct sk_buff *skb,
+ u16 family)
+{
+}
+
+static inline void xfrm_audit_state_notfound(struct sk_buff *skb, u16 family,
+ __be32 net_spi, __be32 net_seq)
+{
+}
+
+static inline void xfrm_audit_state_icvfail(struct xfrm_state *x,
+ struct sk_buff *skb, u8 proto)
+{
+}
#endif /* CONFIG_AUDITSYSCALL */
static inline void xfrm_pol_hold(struct xfrm_policy *policy)
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index 8da627d3380..86ea9e34e32 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -1031,11 +1031,9 @@ int current_cpuset_is_being_rebound(void)
return task_cs(current) == cpuset_being_rebound;
}
-static int update_relax_domain_level(struct cpuset *cs, char *buf)
+static int update_relax_domain_level(struct cpuset *cs, s64 val)
{
- int val = simple_strtol(buf, NULL, 10);
-
- if (val < 0)
+ if ((int)val < 0)
val = -1;
if (val != cs->relax_domain_level) {
@@ -1280,9 +1278,6 @@ static ssize_t cpuset_common_file_write(struct cgroup *cont,
case FILE_MEMLIST:
retval = update_nodemask(cs, buffer);
break;
- case FILE_SCHED_RELAX_DOMAIN_LEVEL:
- retval = update_relax_domain_level(cs, buffer);
- break;
default:
retval = -EINVAL;
goto out2;
@@ -1348,6 +1343,30 @@ static int cpuset_write_u64(struct cgroup *cgrp, struct cftype *cft, u64 val)
return retval;
}
+static int cpuset_write_s64(struct cgroup *cgrp, struct cftype *cft, s64 val)
+{
+ int retval = 0;
+ struct cpuset *cs = cgroup_cs(cgrp);
+ cpuset_filetype_t type = cft->private;
+
+ cgroup_lock();
+
+ if (cgroup_is_removed(cgrp)) {
+ cgroup_unlock();
+ return -ENODEV;
+ }
+ switch (type) {
+ case FILE_SCHED_RELAX_DOMAIN_LEVEL:
+ retval = update_relax_domain_level(cs, val);
+ break;
+ default:
+ retval = -EINVAL;
+ break;
+ }
+ cgroup_unlock();
+ return retval;
+}
+
/*
* These ascii lists should be read in a single call, by using a user
* buffer large enough to hold the entire map. If read in smaller
@@ -1406,9 +1425,6 @@ static ssize_t cpuset_common_file_read(struct cgroup *cont,
case FILE_MEMLIST:
s += cpuset_sprintf_memlist(s, cs);
break;
- case FILE_SCHED_RELAX_DOMAIN_LEVEL:
- s += sprintf(s, "%d", cs->relax_domain_level);
- break;
default:
retval = -EINVAL;
goto out;
@@ -1449,6 +1465,18 @@ static u64 cpuset_read_u64(struct cgroup *cont, struct cftype *cft)
}
}
+static s64 cpuset_read_s64(struct cgroup *cont, struct cftype *cft)
+{
+ struct cpuset *cs = cgroup_cs(cont);
+ cpuset_filetype_t type = cft->private;
+ switch (type) {
+ case FILE_SCHED_RELAX_DOMAIN_LEVEL:
+ return cs->relax_domain_level;
+ default:
+ BUG();
+ }
+}
+
/*
* for the common functions, 'private' gives the type of file
@@ -1499,8 +1527,8 @@ static struct cftype files[] = {
{
.name = "sched_relax_domain_level",
- .read_u64 = cpuset_read_u64,
- .write_u64 = cpuset_write_u64,
+ .read_s64 = cpuset_read_s64,
+ .write_s64 = cpuset_write_s64,
.private = FILE_SCHED_RELAX_DOMAIN_LEVEL,
},
diff --git a/kernel/relay.c b/kernel/relay.c
index 7de644cdec4..bc24dcdc570 100644
--- a/kernel/relay.c
+++ b/kernel/relay.c
@@ -1191,7 +1191,7 @@ static ssize_t relay_file_splice_read(struct file *in,
ret = 0;
spliced = 0;
- while (len && !spliced) {
+ while (len) {
ret = subbuf_splice_actor(in, ppos, pipe, len, flags, &nonpad_ret);
if (ret < 0)
break;
diff --git a/mm/filemap.c b/mm/filemap.c
index 239d36163bb..2dead9adf8b 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -1655,7 +1655,7 @@ int should_remove_suid(struct dentry *dentry)
}
EXPORT_SYMBOL(should_remove_suid);
-int __remove_suid(struct dentry *dentry, int kill)
+static int __remove_suid(struct dentry *dentry, int kill)
{
struct iattr newattrs;
diff --git a/mm/memory.c b/mm/memory.c
index bbab1e37055..48c122d42ed 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -969,7 +969,7 @@ struct page *follow_page(struct vm_area_struct *vma, unsigned long address,
goto no_page_table;
pmd = pmd_offset(pud, address);
- if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd)))
+ if (pmd_none(*pmd))
goto no_page_table;
if (pmd_huge(*pmd)) {
@@ -978,6 +978,9 @@ struct page *follow_page(struct vm_area_struct *vma, unsigned long address,
goto out;
}
+ if (unlikely(pmd_bad(*pmd)))
+ goto no_page_table;
+
ptep = pte_offset_map_lock(mm, pmd, address, &ptl);
if (!ptep)
goto out;
diff --git a/mm/slub.c b/mm/slub.c
index d379b782fc8..a505a828ef4 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -3762,7 +3762,7 @@ static int any_slab_objects(struct kmem_cache *s)
if (!n)
continue;
- if (atomic_read(&n->total_objects))
+ if (atomic_long_read(&n->total_objects))
return 1;
}
return 0;
diff --git a/net/atm/br2684.c b/net/atm/br2684.c
index 1b228065e74..9d52ebfc196 100644
--- a/net/atm/br2684.c
+++ b/net/atm/br2684.c
@@ -346,9 +346,9 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
/* skb==NULL means VCC is being destroyed */
br2684_close_vcc(brvcc);
if (list_empty(&brdev->brvccs)) {
- read_lock(&devs_lock);
+ write_lock_irq(&devs_lock);
list_del(&brdev->br2684_devs);
- read_unlock(&devs_lock);
+ write_unlock_irq(&devs_lock);
unregister_netdev(net_dev);
free_netdev(net_dev);
}
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index 77a981a1ee5..c2397f503b0 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -273,15 +273,13 @@ int br_add_bridge(const char *name)
rtnl_lock();
if (strchr(dev->name, '%')) {
ret = dev_alloc_name(dev, dev->name);
- if (ret < 0) {
- free_netdev(dev);
- goto out;
- }
+ if (ret < 0)
+ goto out_free;
}
ret = register_netdevice(dev);
if (ret)
- goto out;
+ goto out_free;
ret = br_sysfs_addbr(dev);
if (ret)
@@ -289,6 +287,10 @@ int br_add_bridge(const char *name)
out:
rtnl_unlock();
return ret;
+
+out_free:
+ free_netdev(dev);
+ goto out;
}
int br_del_bridge(const char *name)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 4fe605fa6f8..5c459f2b798 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -200,7 +200,9 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
goto nodata;
/*
- * See comment in sk_buff definition, just before the 'tail' member
+ * Only clear those fields we need to clear, not those that we will
+ * actually initialise below. Hence, don't put any more fields after
+ * the tail pointer in struct sk_buff!
*/
memset(skb, 0, offsetof(struct sk_buff, tail));
skb->truesize = size + sizeof(struct sk_buff);
diff --git a/net/dccp/feat.c b/net/dccp/feat.c
index 4a4f6ce4498..933a0ecf8d4 100644
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -32,7 +32,7 @@ int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
if (len > 3) {
DCCP_WARN("invalid length %d\n", len);
- return 1;
+ return -EINVAL;
}
/* XXX add further sanity checks */
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index 2f665a51647..f50e88bf266 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -235,14 +235,14 @@ static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu)
else
min_mtu -= 21;
- if (dst->metrics[RTAX_MTU-1] > mtu && mtu >= min_mtu) {
+ if (dst_metric(dst, RTAX_MTU) > mtu && mtu >= min_mtu) {
if (!(dst_metric_locked(dst, RTAX_MTU))) {
dst->metrics[RTAX_MTU-1] = mtu;
dst_set_expires(dst, dn_rt_mtu_expires);
}
if (!(dst_metric_locked(dst, RTAX_ADVMSS))) {
u32 mss = mtu - DN_MAX_NSP_DATA_HEADER;
- if (dst->metrics[RTAX_ADVMSS-1] > mss)
+ if (dst_metric(dst, RTAX_ADVMSS) > mss)
dst->metrics[RTAX_ADVMSS-1] = mss;
}
}
@@ -805,12 +805,12 @@ static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res)
rt->u.dst.neighbour = n;
}
- if (rt->u.dst.metrics[RTAX_MTU-1] == 0 ||
- rt->u.dst.metrics[RTAX_MTU-1] > rt->u.dst.dev->mtu)
+ if (dst_metric(&rt->u.dst, RTAX_MTU) == 0 ||
+ dst_metric(&rt->u.dst, RTAX_MTU) > rt->u.dst.dev->mtu)
rt->u.dst.metrics[RTAX_MTU-1] = rt->u.dst.dev->mtu;
mss = dn_mss_from_pmtu(dev, dst_mtu(&rt->u.dst));
- if (rt->u.dst.metrics[RTAX_ADVMSS-1] == 0 ||
- rt->u.dst.metrics[RTAX_ADVMSS-1] > mss)
+ if (dst_metric(&rt->u.dst, RTAX_ADVMSS) == 0 ||
+ dst_metric(&rt->u.dst, RTAX_ADVMSS) > mss)
rt->u.dst.metrics[RTAX_ADVMSS-1] = mss;
return 0;
}
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 5e3685c5c40..92f90ae46f4 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1468,14 +1468,14 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph,
/* BSD 4.2 compatibility hack :-( */
if (mtu == 0 &&
- old_mtu >= rth->u.dst.metrics[RTAX_MTU-1] &&
+ old_mtu >= dst_metric(&rth->u.dst, RTAX_MTU) &&
old_mtu >= 68 + (iph->ihl << 2))
old_mtu -= iph->ihl << 2;
mtu = guess_mtu(old_mtu);
}
- if (mtu <= rth->u.dst.metrics[RTAX_MTU-1]) {
- if (mtu < rth->u.dst.metrics[RTAX_MTU-1]) {
+ if (mtu <= dst_metric(&rth->u.dst, RTAX_MTU)) {
+ if (mtu < dst_metric(&rth->u.dst, RTAX_MTU)) {
dst_confirm(&rth->u.dst);
if (mtu < ip_rt_min_pmtu) {
mtu = ip_rt_min_pmtu;
@@ -1497,7 +1497,7 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph,
static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
{
- if (dst->metrics[RTAX_MTU-1] > mtu && mtu >= 68 &&
+ if (dst_metric(dst, RTAX_MTU) > mtu && mtu >= 68 &&
!(dst_metric_locked(dst, RTAX_MTU))) {
if (mtu < ip_rt_min_pmtu) {
mtu = ip_rt_min_pmtu;
@@ -1613,7 +1613,7 @@ static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag)
sizeof(rt->u.dst.metrics));
if (fi->fib_mtu == 0) {
rt->u.dst.metrics[RTAX_MTU-1] = rt->u.dst.dev->mtu;
- if (rt->u.dst.metrics[RTAX_LOCK-1] & (1 << RTAX_MTU) &&
+ if (dst_metric_locked(&rt->u.dst, RTAX_MTU) &&
rt->rt_gateway != rt->rt_dst &&
rt->u.dst.dev->mtu > 576)
rt->u.dst.metrics[RTAX_MTU-1] = 576;
@@ -1624,14 +1624,14 @@ static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag)
} else
rt->u.dst.metrics[RTAX_MTU-1]= rt->u.dst.dev->mtu;
- if (rt->u.dst.metrics[RTAX_HOPLIMIT-1] == 0)
+ if (dst_metric(&rt->u.dst, RTAX_HOPLIMIT) == 0)
rt->u.dst.metrics[RTAX_HOPLIMIT-1] = sysctl_ip_default_ttl;
- if (rt->u.dst.metrics[RTAX_MTU-1] > IP_MAX_MTU)
+ if (dst_metric(&rt->u.dst, RTAX_MTU) > IP_MAX_MTU)
rt->u.dst.metrics[RTAX_MTU-1] = IP_MAX_MTU;
- if (rt->u.dst.metrics[RTAX_ADVMSS-1] == 0)
+ if (dst_metric(&rt->u.dst, RTAX_ADVMSS) == 0)
rt->u.dst.metrics[RTAX_ADVMSS-1] = max_t(unsigned int, rt->u.dst.dev->mtu - 40,
ip_rt_min_advmss);
- if (rt->u.dst.metrics[RTAX_ADVMSS-1] > 65535 - 40)
+ if (dst_metric(&rt->u.dst, RTAX_ADVMSS) > 65535 - 40)
rt->u.dst.metrics[RTAX_ADVMSS-1] = 65535 - 40;
#ifdef CONFIG_NET_CLS_ROUTE
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index eda4f4a233f..8ac15a604e0 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -66,6 +66,7 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/sysctl.h>
+#include <net/dst.h>
#include <net/tcp.h>
#include <net/inet_common.h>
#include <linux/ipsec.h>
@@ -605,7 +606,7 @@ static u32 tcp_rto_min(struct sock *sk)
u32 rto_min = TCP_RTO_MIN;
if (dst && dst_metric_locked(dst, RTAX_RTO_MIN))
- rto_min = dst->metrics[RTAX_RTO_MIN - 1];
+ rto_min = dst_metric(dst, RTAX_RTO_MIN);
return rto_min;
}
@@ -769,7 +770,7 @@ void tcp_update_metrics(struct sock *sk)
dst->metrics[RTAX_RTTVAR - 1] = m;
else
dst->metrics[RTAX_RTTVAR-1] -=
- (dst->metrics[RTAX_RTTVAR-1] - m)>>2;
+ (dst_metric(dst, RTAX_RTTVAR) - m)>>2;
}
if (tp->snd_ssthresh >= 0xFFFF) {
@@ -788,21 +789,21 @@ void tcp_update_metrics(struct sock *sk)
dst->metrics[RTAX_SSTHRESH-1] =
max(tp->snd_cwnd >> 1, tp->snd_ssthresh);
if (!dst_metric_locked(dst, RTAX_CWND))
- dst->metrics[RTAX_CWND-1] = (dst->metrics[RTAX_CWND-1] + tp->snd_cwnd) >> 1;
+ dst->metrics[RTAX_CWND-1] = (dst_metric(dst, RTAX_CWND) + tp->snd_cwnd) >> 1;
} else {
/* Else slow start did not finish, cwnd is non-sense,
ssthresh may be also invalid.
*/
if (!dst_metric_locked(dst, RTAX_CWND))
- dst->metrics[RTAX_CWND-1] = (dst->metrics[RTAX_CWND-1] + tp->snd_ssthresh) >> 1;
- if (dst->metrics[RTAX_SSTHRESH-1] &&
+ dst->metrics[RTAX_CWND-1] = (dst_metric(dst, RTAX_CWND) + tp->snd_ssthresh) >> 1;
+ if (dst_metric(dst, RTAX_SSTHRESH) &&
!dst_metric_locked(dst, RTAX_SSTHRESH) &&
- tp->snd_ssthresh > dst->metrics[RTAX_SSTHRESH-1])
+ tp->snd_ssthresh > dst_metric(dst, RTAX_SSTHRESH))
dst->metrics[RTAX_SSTHRESH-1] = tp->snd_ssthresh;
}
if (!dst_metric_locked(dst, RTAX_REORDERING)) {
- if (dst->metrics[RTAX_REORDERING-1] < tp->reordering &&
+ if (dst_metric(dst, RTAX_REORDERING) < tp->reordering &&
tp->reordering != sysctl_tcp_reordering)
dst->metrics[RTAX_REORDERING-1] = tp->reordering;
}
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index a493ad9b891..12bba088034 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1243,11 +1243,11 @@ install_route:
}
}
- if (rt->u.dst.metrics[RTAX_HOPLIMIT-1] == 0)
+ if (dst_metric(&rt->u.dst, RTAX_HOPLIMIT) == 0)
rt->u.dst.metrics[RTAX_HOPLIMIT-1] = -1;
- if (!rt->u.dst.metrics[RTAX_MTU-1])
+ if (!dst_metric(&rt->u.dst, RTAX_MTU))
rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(dev);
- if (!rt->u.dst.metrics[RTAX_ADVMSS-1])
+ if (!dst_metric(&rt->u.dst, RTAX_ADVMSS))
rt->u.dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->u.dst));
rt->u.dst.dev = dev;
rt->rt6i_idev = idev;
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 9ad4e3631b6..915afadb060 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -1766,6 +1766,7 @@ fail_wep:
fail_rate:
ieee80211_debugfs_remove_netdev(IEEE80211_DEV_TO_SUB_IF(local->mdev));
unregister_netdevice(local->mdev);
+ local->mdev = NULL;
fail_dev:
rtnl_unlock();
sta_info_stop(local);
@@ -1773,8 +1774,10 @@ fail_sta_info:
debugfs_hw_del(local);
destroy_workqueue(local->hw.workqueue);
fail_workqueue:
- ieee80211_if_free(local->mdev);
- local->mdev = NULL;
+ if (local->mdev != NULL) {
+ ieee80211_if_free(local->mdev);
+ local->mdev = NULL;
+ }
fail_mdev_alloc:
wiphy_unregister(local->hw.wiphy);
return result;
diff --git a/net/mac80211/rc80211_pid_debugfs.c b/net/mac80211/rc80211_pid_debugfs.c
index ae75d417873..ff5c380f3c1 100644
--- a/net/mac80211/rc80211_pid_debugfs.c
+++ b/net/mac80211/rc80211_pid_debugfs.c
@@ -85,7 +85,7 @@ static int rate_control_pid_events_open(struct inode *inode, struct file *file)
struct rc_pid_sta_info *sinfo = inode->i_private;
struct rc_pid_event_buffer *events = &sinfo->events;
struct rc_pid_events_file_info *file_info;
- unsigned int status;
+ unsigned long status;
/* Allocate a state struct */
file_info = kmalloc(sizeof(*file_info), GFP_KERNEL);
@@ -135,7 +135,7 @@ static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf,
char pb[RC_PID_PRINT_BUF_SIZE];
int ret;
int p;
- unsigned int status;
+ unsigned long status;
/* Check if there is something to read. */
if (events->next_entry == file_info->next_entry) {
diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c
index 64b2d136c78..1d421d059ca 100644
--- a/net/sched/act_simple.c
+++ b/net/sched/act_simple.c
@@ -6,7 +6,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Authors: Jamal Hadi Salim (2005)
+ * Authors: Jamal Hadi Salim (2005-8)
*
*/
@@ -34,6 +34,7 @@ static struct tcf_hashinfo simp_hash_info = {
.lock = &simp_lock,
};
+#define SIMP_MAX_DATA 32
static int tcf_simp(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res)
{
struct tcf_defact *d = a->priv;
@@ -69,23 +70,28 @@ static int tcf_simp_release(struct tcf_defact *d, int bind)
return ret;
}
-static int alloc_defdata(struct tcf_defact *d, u32 datalen, void *defdata)
+static int alloc_defdata(struct tcf_defact *d, char *defdata)
{
- d->tcfd_defdata = kmemdup(defdata, datalen, GFP_KERNEL);
+ d->tcfd_defdata = kstrndup(defdata, SIMP_MAX_DATA, GFP_KERNEL);
if (unlikely(!d->tcfd_defdata))
return -ENOMEM;
- d->tcfd_datalen = datalen;
+
return 0;
}
-static int realloc_defdata(struct tcf_defact *d, u32 datalen, void *defdata)
+static void reset_policy(struct tcf_defact *d, char *defdata,
+ struct tc_defact *p)
{
- kfree(d->tcfd_defdata);
- return alloc_defdata(d, datalen, defdata);
+ spin_lock_bh(&d->tcf_lock);
+ d->tcf_action = p->action;
+ memset(d->tcfd_defdata, 0, SIMP_MAX_DATA);
+ strlcpy(d->tcfd_defdata, defdata, SIMP_MAX_DATA);
+ spin_unlock_bh(&d->tcf_lock);
}
static const struct nla_policy simple_policy[TCA_DEF_MAX + 1] = {
[TCA_DEF_PARMS] = { .len = sizeof(struct tc_defact) },
+ [TCA_DEF_DATA] = { .type = NLA_STRING, .len = SIMP_MAX_DATA },
};
static int tcf_simp_init(struct nlattr *nla, struct nlattr *est,
@@ -95,28 +101,24 @@ static int tcf_simp_init(struct nlattr *nla, struct nlattr *est,
struct tc_defact *parm;
struct tcf_defact *d;
struct tcf_common *pc;
- void *defdata;
- u32 datalen = 0;
+ char *defdata;
int ret = 0, err;
if (nla == NULL)
return -EINVAL;
- err = nla_parse_nested(tb, TCA_DEF_MAX, nla, NULL);
+ err = nla_parse_nested(tb, TCA_DEF_MAX, nla, simple_policy);
if (err < 0)
return err;
if (tb[TCA_DEF_PARMS] == NULL)
return -EINVAL;
- parm = nla_data(tb[TCA_DEF_PARMS]);
- defdata = nla_data(tb[TCA_DEF_DATA]);
- if (defdata == NULL)
+ if (tb[TCA_DEF_DATA] == NULL)
return -EINVAL;
- datalen = nla_len(tb[TCA_DEF_DATA]);
- if (datalen == 0)
- return -EINVAL;
+ parm = nla_data(tb[TCA_DEF_PARMS]);
+ defdata = nla_data(tb[TCA_DEF_DATA]);
pc = tcf_hash_check(parm->index, a, bind, &simp_hash_info);
if (!pc) {
@@ -126,11 +128,12 @@ static int tcf_simp_init(struct nlattr *nla, struct nlattr *est,
return -ENOMEM;
d = to_defact(pc);
- ret = alloc_defdata(d, datalen, defdata);
+ ret = alloc_defdata(d, defdata);
if (ret < 0) {
kfree(pc);
return ret;
}
+ d->tcf_action = parm->action;
ret = ACT_P_CREATED;
} else {
d = to_defact(pc);
@@ -138,13 +141,9 @@ static int tcf_simp_init(struct nlattr *nla, struct nlattr *est,
tcf_simp_release(d, bind);
return -EEXIST;
}
- realloc_defdata(d, datalen, defdata);
+ reset_policy(d, defdata, parm);
}
- spin_lock_bh(&d->tcf_lock);
- d->tcf_action = parm->action;
- spin_unlock_bh(&d->tcf_lock);
-
if (ret == ACT_P_CREATED)
tcf_hash_insert(pc, &simp_hash_info);
return ret;
@@ -172,7 +171,7 @@ static inline int tcf_simp_dump(struct sk_buff *skb, struct tc_action *a,
opt.bindcnt = d->tcf_bindcnt - bind;
opt.action = d->tcf_action;
NLA_PUT(skb, TCA_DEF_PARMS, sizeof(opt), &opt);
- NLA_PUT(skb, TCA_DEF_DATA, d->tcfd_datalen, d->tcfd_defdata);
+ NLA_PUT_STRING(skb, TCA_DEF_DATA, d->tcfd_defdata);
t.install = jiffies_to_clock_t(jiffies - d->tcf_tm.install);
t.lastuse = jiffies_to_clock_t(jiffies - d->tcf_tm.lastuse);
t.expires = jiffies_to_clock_t(d->tcf_tm.expires);
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 66148cc4759..5bc1ed49018 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -1197,12 +1197,16 @@ static inline int htb_parent_last_child(struct htb_class *cl)
return 1;
}
-static void htb_parent_to_leaf(struct htb_class *cl, struct Qdisc *new_q)
+static void htb_parent_to_leaf(struct htb_sched *q, struct htb_class *cl,
+ struct Qdisc *new_q)
{
struct htb_class *parent = cl->parent;
BUG_TRAP(!cl->level && cl->un.leaf.q && !cl->prio_activity);
+ if (parent->cmode != HTB_CAN_SEND)
+ htb_safe_rb_erase(&parent->pq_node, q->wait_pq + parent->level);
+
parent->level = 0;
memset(&parent->un.inner, 0, sizeof(parent->un.inner));
INIT_LIST_HEAD(&parent->un.leaf.drop_list);
@@ -1300,7 +1304,7 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
htb_deactivate(q, cl);
if (last_child)
- htb_parent_to_leaf(cl, new_q);
+ htb_parent_to_leaf(q, cl, new_q);
if (--cl->refcnt == 0)
htb_destroy_class(sch, cl);
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index d74c2d26953..01c7e311b90 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -18,7 +18,6 @@
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/module.h>
-#include <linux/sched.h>
#include <linux/sunrpc/types.h>
#include <linux/sunrpc/xdr.h>
diff --git a/sound/oss/kahlua.c b/sound/oss/kahlua.c
index dfe670f12e6..eb9bc365530 100644
--- a/sound/oss/kahlua.c
+++ b/sound/oss/kahlua.c
@@ -67,7 +67,7 @@ static int __devinit probe_one(struct pci_dev *pdev, const struct pci_device_id
return 1;
mem = ioremap(base, 128);
- if(mem == 0UL)
+ if (!mem)
return 1;
map = readw(mem + 0x18); /* Read the SMI enables */
iounmap(mem);