aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CREDITS2
-rw-r--r--Documentation/cputopology.txt41
-rw-r--r--Documentation/driver-model/overview.txt57
-rw-r--r--Documentation/filesystems/configfs/configfs_example.c2
-rw-r--r--Documentation/filesystems/ocfs2.txt1
-rw-r--r--Documentation/networking/ip-sysctl.txt17
-rw-r--r--Documentation/parport-lowlevel.txt8
-rw-r--r--Documentation/pci-error-recovery.txt472
-rw-r--r--Documentation/x86_64/boot-options.txt12
-rw-r--r--MAINTAINERS6
-rw-r--r--Makefile2
-rw-r--r--arch/arm/configs/at91rm9200dk_defconfig1
-rw-r--r--arch/arm/configs/at91rm9200ek_defconfig1
-rw-r--r--arch/arm/configs/csb337_defconfig1
-rw-r--r--arch/arm/configs/csb637_defconfig1
-rw-r--r--arch/arm/mach-pxa/pxa27x.c2
-rw-r--r--arch/arm/mach-s3c2410/Makefile5
-rw-r--r--arch/arm/mach-s3c2410/cpu.c18
-rw-r--r--arch/arm/mach-s3c2410/gpio.c72
-rw-r--r--arch/arm/mach-s3c2410/s3c2400-gpio.c45
-rw-r--r--arch/arm/mach-s3c2410/s3c2410-gpio.c93
-rw-r--r--arch/arm/mach-s3c2410/sleep.S2
-rw-r--r--arch/arm/mm/cache-v6.S18
-rw-r--r--arch/arm/mm/proc-xscale.S16
-rw-r--r--arch/arm/oprofile/common.c5
-rw-r--r--arch/i386/Kconfig1
-rw-r--r--arch/i386/kernel/acpi/boot.c13
-rw-r--r--arch/i386/kernel/apic.c5
-rw-r--r--arch/i386/kernel/cpu/amd.c8
-rw-r--r--arch/i386/kernel/cpu/centaur.c8
-rw-r--r--arch/i386/kernel/cpu/common.c11
-rw-r--r--arch/i386/kernel/cpu/cyrix.c18
-rw-r--r--arch/i386/kernel/cpu/intel_cacheinfo.c1
-rw-r--r--arch/i386/kernel/cpu/nexgen.c8
-rw-r--r--arch/i386/kernel/cpu/rise.c8
-rw-r--r--arch/i386/kernel/cpu/transmeta.c10
-rw-r--r--arch/i386/kernel/cpu/umc.c8
-rw-r--r--arch/i386/kernel/nmi.c2
-rw-r--r--arch/i386/kernel/process.c6
-rw-r--r--arch/i386/kernel/traps.c9
-rw-r--r--arch/i386/oprofile/backtrace.c19
-rw-r--r--arch/ia64/kernel/topology.c18
-rw-r--r--arch/parisc/Kconfig20
-rw-r--r--arch/parisc/Kconfig.debug10
-rw-r--r--arch/parisc/configs/b180_defconfig182
-rw-r--r--arch/parisc/hpux/entry_hpux.S3
-rw-r--r--arch/parisc/kernel/drivers.c3
-rw-r--r--arch/parisc/kernel/parisc_ksyms.c3
-rw-r--r--arch/parisc/kernel/pci.c13
-rw-r--r--arch/parisc/kernel/perf.c38
-rw-r--r--arch/parisc/kernel/perf_images.h4
-rw-r--r--arch/parisc/kernel/process.c35
-rw-r--r--arch/parisc/kernel/ptrace.c8
-rw-r--r--arch/parisc/kernel/signal.c2
-rw-r--r--arch/parisc/kernel/signal32.c102
-rw-r--r--arch/parisc/kernel/signal32.h127
-rw-r--r--arch/parisc/kernel/syscall.S2
-rw-r--r--arch/parisc/kernel/syscall_table.S19
-rw-r--r--arch/parisc/kernel/traps.c3
-rw-r--r--arch/parisc/math-emu/decode_exc.c1
-rw-r--r--arch/parisc/mm/init.c35
-rw-r--r--arch/s390/kernel/compat_wrapper.S6
-rw-r--r--arch/sparc64/boot/.gitignore4
-rw-r--r--arch/sparc64/defconfig21
-rw-r--r--arch/v850/kernel/simcons.c25
-rw-r--r--arch/x86_64/Kconfig.debug7
-rw-r--r--arch/x86_64/defconfig21
-rw-r--r--arch/x86_64/kernel/apic.c89
-rw-r--r--arch/x86_64/kernel/entry.S7
-rw-r--r--arch/x86_64/kernel/io_apic.c8
-rw-r--r--arch/x86_64/kernel/mce.c2
-rw-r--r--arch/x86_64/kernel/nmi.c7
-rw-r--r--arch/x86_64/kernel/pci-dma.c3
-rw-r--r--arch/x86_64/kernel/pci-gart.c19
-rw-r--r--arch/x86_64/kernel/pci-nommu.c7
-rw-r--r--arch/x86_64/kernel/pci-swiotlb.c2
-rw-r--r--arch/x86_64/kernel/pmtimer.c25
-rw-r--r--arch/x86_64/kernel/process.c4
-rw-r--r--arch/x86_64/kernel/setup.c8
-rw-r--r--arch/x86_64/kernel/time.c59
-rw-r--r--arch/x86_64/kernel/traps.c21
-rw-r--r--arch/x86_64/kernel/vmlinux.lds.S10
-rw-r--r--arch/x86_64/lib/clear_page.S38
-rw-r--r--arch/x86_64/lib/copy_page.S87
-rw-r--r--arch/x86_64/lib/copy_user.S247
-rw-r--r--arch/x86_64/lib/memcpy.S93
-rw-r--r--arch/x86_64/lib/memset.S94
-rw-r--r--arch/x86_64/mm/fault.c3
-rw-r--r--arch/x86_64/mm/srat.c45
-rw-r--r--arch/x86_64/pci/mmconfig.c2
-rw-r--r--arch/xtensa/platform-iss/console.c4
-rw-r--r--block/elevator.c3
-rw-r--r--block/ll_rw_blk.c40
-rw-r--r--drivers/acpi/processor_idle.c6
-rw-r--r--drivers/base/Makefile1
-rw-r--r--drivers/base/topology.c148
-rw-r--r--drivers/block/Kconfig8
-rw-r--r--drivers/block/pktcdvd.c58
-rw-r--r--drivers/block/umem.c2
-rw-r--r--drivers/char/cyclades.c6
-rw-r--r--drivers/char/drm/ati_pcigart.c17
-rw-r--r--drivers/char/drm/drmP.h5
-rw-r--r--drivers/char/drm/drm_auth.c20
-rw-r--r--drivers/char/drm/drm_bufs.c80
-rw-r--r--drivers/char/drm/drm_context.c52
-rw-r--r--drivers/char/drm/drm_drv.c4
-rw-r--r--drivers/char/drm/drm_fops.c12
-rw-r--r--drivers/char/drm/drm_ioctl.c18
-rw-r--r--drivers/char/drm/drm_irq.c16
-rw-r--r--drivers/char/drm/drm_pciids.h2
-rw-r--r--drivers/char/drm/drm_proc.c28
-rw-r--r--drivers/char/drm/drm_stub.c4
-rw-r--r--drivers/char/drm/drm_vm.c12
-rw-r--r--drivers/char/drm/i810_dma.c2
-rw-r--r--drivers/char/drm/i810_drv.h2
-rw-r--r--drivers/char/drm/i830_dma.c2
-rw-r--r--drivers/char/drm/i830_drv.h3
-rw-r--r--drivers/char/drm/i915_dma.c42
-rw-r--r--drivers/char/drm/i915_drm.h33
-rw-r--r--drivers/char/drm/i915_drv.h6
-rw-r--r--drivers/char/drm/i915_mem.c31
-rw-r--r--drivers/char/drm/radeon_cp.c2
-rw-r--r--drivers/char/drm/savage_bci.c4
-rw-r--r--drivers/char/drm/savage_drv.h1
-rw-r--r--drivers/char/drm/via_dma.c10
-rw-r--r--drivers/char/drm/via_dmablit.c6
-rw-r--r--drivers/char/drm/via_drv.h7
-rw-r--r--drivers/char/drm/via_irq.c2
-rw-r--r--drivers/char/esp.c4
-rw-r--r--drivers/char/ip2/i2cmd.c1
-rw-r--r--drivers/char/ip2main.c67
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c4
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c24
-rw-r--r--drivers/char/rio/cirrus.h142
-rw-r--r--drivers/char/rio/defaults.h7
-rw-r--r--drivers/char/rio/link.h34
-rw-r--r--drivers/char/rio/list.h140
-rw-r--r--drivers/char/rio/parmmap.h5
-rw-r--r--drivers/char/rio/phb.h133
-rw-r--r--drivers/char/rio/pkt.h27
-rw-r--r--drivers/char/rio/qbuf.h4
-rw-r--r--drivers/char/rio/riotypes.h66
-rw-r--r--drivers/char/rio/rup.h5
-rw-r--r--drivers/char/rio/sam.h4
-rw-r--r--drivers/char/rocket.c2
-rw-r--r--drivers/char/sx.c6
-rw-r--r--drivers/char/tty_io.c77
-rw-r--r--drivers/char/watchdog/sbc_epx_c3.c13
-rw-r--r--drivers/edac/Kconfig3
-rw-r--r--drivers/edac/e752x_edac.c8
-rw-r--r--drivers/edac/edac_mc.c1
-rw-r--r--drivers/ide/Kconfig25
-rw-r--r--drivers/ide/ide-disk.c8
-rw-r--r--drivers/ide/ide-io.c5
-rw-r--r--drivers/ide/ide-iops.c1
-rw-r--r--drivers/ide/ide-probe.c51
-rw-r--r--drivers/ide/ide.c1
-rw-r--r--drivers/ide/pci/aec62xx.c15
-rw-r--r--drivers/ide/pci/hpt366.c4
-rw-r--r--drivers/ide/pci/it821x.c2
-rw-r--r--drivers/ide/pci/pdc202xx_new.c6
-rw-r--r--drivers/ide/pci/pdc202xx_old.c15
-rw-r--r--drivers/ide/pci/piix.c4
-rw-r--r--drivers/isdn/hisax/hisax.h2
-rw-r--r--drivers/isdn/sc/ioctl.c4
-rw-r--r--drivers/md/dm-log.c3
-rw-r--r--drivers/md/md.c48
-rw-r--r--drivers/md/raid0.c2
-rw-r--r--drivers/md/raid10.c2
-rw-r--r--drivers/md/raid5.c3
-rw-r--r--drivers/md/raid6main.c152
-rw-r--r--drivers/message/i2o/core.h3
-rw-r--r--drivers/message/i2o/i2o_scsi.c2
-rw-r--r--drivers/message/i2o/pci.c47
-rw-r--r--drivers/mmc/au1xmmc.c59
-rw-r--r--drivers/mmc/mmc.c28
-rw-r--r--drivers/mmc/mmc_block.c8
-rw-r--r--drivers/mmc/mmci.c11
-rw-r--r--drivers/mmc/pxamci.c9
-rw-r--r--drivers/mmc/wbsd.c8
-rw-r--r--drivers/mtd/maps/dc21285.c9
-rw-r--r--drivers/net/3c59x.c33
-rw-r--r--drivers/net/ppp_generic.c3
-rw-r--r--drivers/net/tg3.c30
-rw-r--r--drivers/net/tg3.h1
-rw-r--r--drivers/parisc/ccio-dma.c7
-rw-r--r--drivers/parisc/dino.c4
-rw-r--r--drivers/parisc/hppb.c3
-rw-r--r--drivers/parisc/iosapic.c8
-rw-r--r--drivers/parisc/lasi.c5
-rw-r--r--drivers/parisc/lba_pci.c6
-rw-r--r--drivers/parisc/pdc_stable.c356
-rw-r--r--drivers/parisc/sba_iommu.c3
-rw-r--r--drivers/parisc/superio.c41
-rw-r--r--drivers/parisc/wax.c2
-rw-r--r--drivers/parport/Kconfig9
-rw-r--r--drivers/parport/Makefile1
-rw-r--r--drivers/parport/ieee1284.c10
-rw-r--r--drivers/parport/parport_gsc.c2
-rw-r--r--drivers/parport/parport_ip32.c2253
-rw-r--r--drivers/parport/parport_serial.c4
-rw-r--r--drivers/parport/probe.c4
-rw-r--r--drivers/s390/block/Kconfig14
-rw-r--r--drivers/s390/block/Makefile2
-rw-r--r--drivers/s390/block/dasd.c76
-rw-r--r--drivers/s390/block/dasd_3990_erp.c3
-rw-r--r--drivers/s390/block/dasd_eckd.h1
-rw-r--r--drivers/s390/block/dasd_eer.c1090
-rw-r--r--drivers/s390/block/dasd_int.h37
-rw-r--r--drivers/s390/cio/chsc.h2
-rw-r--r--drivers/scsi/scsi.c2
-rw-r--r--drivers/serial/8250_pci.c25
-rw-r--r--drivers/serial/Kconfig29
-rw-r--r--drivers/serial/jsm/jsm.h1
-rw-r--r--drivers/serial/jsm/jsm_driver.c3
-rw-r--r--drivers/serial/jsm/jsm_tty.c209
-rw-r--r--drivers/serial/mcfserial.c3
-rw-r--r--drivers/serial/serial_core.c2
-rw-r--r--drivers/telephony/ixj.c14
-rw-r--r--drivers/usb/core/driver.c6
-rw-r--r--drivers/video/console/sticore.c45
-rw-r--r--fs/9p/conv.c28
-rw-r--r--fs/9p/mux.c15
-rw-r--r--fs/9p/vfs_inode.c6
-rw-r--r--fs/Kconfig2
-rw-r--r--fs/buffer.c4
-rw-r--r--fs/configfs/configfs_internal.h11
-rw-r--r--fs/configfs/dir.c36
-rw-r--r--fs/configfs/file.c19
-rw-r--r--fs/configfs/inode.c120
-rw-r--r--fs/configfs/mount.c28
-rw-r--r--fs/configfs/symlink.c4
-rw-r--r--fs/dcache.c2
-rw-r--r--fs/direct-io.c9
-rw-r--r--fs/ext2/acl.c2
-rw-r--r--fs/ext2/ialloc.c2
-rw-r--r--fs/ext2/super.c5
-rw-r--r--fs/ext3/acl.c2
-rw-r--r--fs/fat/file.c50
-rw-r--r--fs/fat/misc.c14
-rw-r--r--fs/fcntl.c7
-rw-r--r--fs/file.c3
-rw-r--r--fs/fuse/dev.c40
-rw-r--r--fs/jbd/transaction.c10
-rw-r--r--fs/jffs/intrep.c2
-rw-r--r--fs/libfs.c1
-rw-r--r--fs/lockd/clntproc.c11
-rw-r--r--fs/namei.c37
-rw-r--r--fs/nfs/direct.c2
-rw-r--r--fs/ocfs2/buffer_head_io.c10
-rw-r--r--fs/ocfs2/cluster/heartbeat.c5
-rw-r--r--fs/ocfs2/cluster/tcp.c16
-rw-r--r--fs/ocfs2/dlm/dlmcommon.h1
-rw-r--r--fs/ocfs2/dlm/dlmdomain.c18
-rw-r--r--fs/ocfs2/dlm/dlmmaster.c24
-rw-r--r--fs/ocfs2/dlm/dlmrecovery.c250
-rw-r--r--fs/ocfs2/dlm/dlmunlock.c13
-rw-r--r--fs/ocfs2/dlm/userdlm.c2
-rw-r--r--fs/ocfs2/extent_map.c12
-rw-r--r--fs/ocfs2/file.c10
-rw-r--r--fs/ocfs2/inode.c6
-rw-r--r--fs/ocfs2/inode.h4
-rw-r--r--fs/ocfs2/journal.c32
-rw-r--r--fs/ocfs2/ocfs2.h3
-rw-r--r--fs/ocfs2/super.c11
-rw-r--r--fs/ocfs2/sysfile.c6
-rw-r--r--fs/ocfs2/uptodate.c12
-rw-r--r--fs/ocfs2/uptodate.h2
-rw-r--r--fs/proc/proc_misc.c2
-rw-r--r--fs/quota_v2.c2
-rw-r--r--fs/reiserfs/super.c2
-rw-r--r--fs/udf/balloc.c7
-rw-r--r--fs/udf/namei.c4
-rw-r--r--fs/ufs/inode.c2
-rw-r--r--fs/ufs/super.c10
-rw-r--r--fs/ufs/truncate.c72
-rw-r--r--include/asm-arm/arch-s3c2410/hardware.h7
-rw-r--r--include/asm-arm/arch-s3c2410/regs-gpio.h22
-rw-r--r--include/asm-arm/checksum.h2
-rw-r--r--include/asm-cris/bitops.h2
-rw-r--r--include/asm-frv/bitops.h2
-rw-r--r--include/asm-h8300/bitops.h2
-rw-r--r--include/asm-i386/system.h2
-rw-r--r--include/asm-i386/topology.h9
-rw-r--r--include/asm-ia64/ide.h8
-rw-r--r--include/asm-ia64/topology.h7
-rw-r--r--include/asm-parisc/atomic.h84
-rw-r--r--include/asm-parisc/cacheflush.h6
-rw-r--r--include/asm-parisc/compat_ucontext.h3
-rw-r--r--include/asm-parisc/grfioctl.h2
-rw-r--r--include/asm-parisc/pci.h17
-rw-r--r--include/asm-parisc/pgalloc.h1
-rw-r--r--include/asm-parisc/pgtable.h2
-rw-r--r--include/asm-parisc/rt_sigframe.h4
-rw-r--r--include/asm-parisc/unistd.h21
-rw-r--r--include/asm-s390/dasd.h13
-rw-r--r--include/asm-s390/io.h6
-rw-r--r--include/asm-s390/timer.h8
-rw-r--r--include/asm-v850/bitops.h2
-rw-r--r--include/asm-x86_64/apic.h1
-rw-r--r--include/asm-x86_64/cpufeature.h2
-rw-r--r--include/asm-x86_64/hardirq.h21
-rw-r--r--include/asm-x86_64/kexec.h3
-rw-r--r--include/asm-x86_64/proto.h11
-rw-r--r--include/asm-x86_64/system.h2
-rw-r--r--include/asm-x86_64/topology.h9
-rw-r--r--include/linux/bitops.h2
-rw-r--r--include/linux/configfs.h2
-rw-r--r--include/linux/dcache.h2
-rw-r--r--include/linux/elfcore.h1
-rw-r--r--include/linux/i2o.h6
-rw-r--r--include/linux/ide.h2
-rw-r--r--include/linux/jbd.h4
-rw-r--r--include/linux/kbd_kern.h5
-rw-r--r--include/linux/list.h14
-rw-r--r--include/linux/lockd/lockd.h2
-rw-r--r--include/linux/mmc/mmc.h35
-rw-r--r--include/linux/mmc/protocol.h2
-rw-r--r--include/linux/netfilter_ipv4/ipt_connbytes.h4
-rw-r--r--include/linux/netfilter_ipv4/ipt_policy.h22
-rw-r--r--include/linux/netfilter_ipv6/ip6t_policy.h22
-rw-r--r--include/linux/parport.h6
-rw-r--r--include/linux/pci_ids.h3
-rw-r--r--include/linux/pktcdvd.h8
-rw-r--r--include/linux/quotaops.h1
-rw-r--r--include/linux/rcupdate.h5
-rw-r--r--include/linux/reiserfs_acl.h6
-rw-r--r--include/linux/security.h4
-rw-r--r--include/linux/sunrpc/auth.h10
-rw-r--r--include/linux/suspend.h4
-rw-r--r--include/linux/tty.h2
-rw-r--r--include/linux/tty_flip.h7
-rw-r--r--include/linux/ufs_fs.h14
-rw-r--r--include/linux/ufs_fs_sb.h2
-rw-r--r--include/net/netfilter/nf_conntrack_l3proto.h15
-rw-r--r--include/net/sctp/structs.h2
-rw-r--r--include/net/sock.h8
-rw-r--r--init/Kconfig11
-rw-r--r--kernel/cpuset.c2
-rw-r--r--kernel/intermodule.c3
-rw-r--r--kernel/kprobes.c36
-rw-r--r--kernel/module.c3
-rw-r--r--kernel/sched.c16
-rw-r--r--kernel/signal.c2
-rw-r--r--kernel/time.c13
-rw-r--r--lib/int_sqrt.c2
-rw-r--r--lib/ts_bm.c40
-rw-r--r--mm/hugetlb.c9
-rw-r--r--mm/mempolicy.c2
-rw-r--r--mm/page_alloc.c10
-rw-r--r--mm/slab.c176
-rw-r--r--net/802/psnap.c2
-rw-r--r--net/Kconfig7
-rw-r--r--net/bridge/netfilter/ebt_ulog.c10
-rw-r--r--net/bridge/netfilter/ebtables.c7
-rw-r--r--net/core/dev.c2
-rw-r--r--net/core/utils.c4
-rw-r--r--net/ipv4/icmp.c5
-rw-r--r--net/ipv4/multipath_wrandom.c8
-rw-r--r--net/ipv4/netfilter/arp_tables.c7
-rw-r--r--net/ipv4/netfilter/ip_conntrack_netlink.c3
-rw-r--r--net/ipv4/netfilter/ip_conntrack_tftp.c1
-rw-r--r--net/ipv4/netfilter/ip_nat_standalone.c4
-rw-r--r--net/ipv4/netfilter/ip_tables.c7
-rw-r--r--net/ipv4/netfilter/ipt_ULOG.c26
-rw-r--r--net/ipv4/netfilter/ipt_policy.c11
-rw-r--r--net/ipv4/proc.c2
-rw-r--r--net/ipv6/addrconf.c6
-rw-r--r--net/ipv6/af_inet6.c6
-rw-r--r--net/ipv6/netfilter/ip6_tables.c7
-rw-r--r--net/ipv6/netfilter/ip6t_policy.c7
-rw-r--r--net/ipv6/proc.c2
-rw-r--r--net/netfilter/nf_conntrack_core.c2
-rw-r--r--net/netfilter/nf_conntrack_ftp.c2
-rw-r--r--net/netfilter/nf_conntrack_netlink.c3
-rw-r--r--net/netfilter/nfnetlink_log.c20
-rw-r--r--net/netfilter/nfnetlink_queue.c3
-rw-r--r--net/sctp/output.c2
-rw-r--r--net/sctp/outqueue.c12
-rw-r--r--net/socket.c2
-rw-r--r--net/sunrpc/auth.c25
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c40
-rw-r--r--net/sunrpc/auth_unix.c6
-rw-r--r--net/sunrpc/rpc_pipe.c102
-rw-r--r--scripts/kconfig/Makefile12
-rw-r--r--security/keys/keyctl.c15
-rw-r--r--security/selinux/Kconfig2
-rw-r--r--security/selinux/Makefile4
-rw-r--r--security/selinux/hooks.c21
-rw-r--r--sound/arm/aaci.c14
390 files changed, 8381 insertions, 2867 deletions
diff --git a/CREDITS b/CREDITS
index 8e577ce4abe..6957ef4efab 100644
--- a/CREDITS
+++ b/CREDITS
@@ -3101,7 +3101,7 @@ S: Minto, NSW, 2566
S: Australia
N: Stephen Smalley
-E: sds@epoch.ncsc.mil
+E: sds@tycho.nsa.gov
D: portions of the Linux Security Module (LSM) framework and security modules
N: Chris Smith
diff --git a/Documentation/cputopology.txt b/Documentation/cputopology.txt
new file mode 100644
index 00000000000..ff280e2e161
--- /dev/null
+++ b/Documentation/cputopology.txt
@@ -0,0 +1,41 @@
+
+Export cpu topology info by sysfs. Items (attributes) are similar
+to /proc/cpuinfo.
+
+1) /sys/devices/system/cpu/cpuX/topology/physical_package_id:
+represent the physical package id of cpu X;
+2) /sys/devices/system/cpu/cpuX/topology/core_id:
+represent the cpu core id to cpu X;
+3) /sys/devices/system/cpu/cpuX/topology/thread_siblings:
+represent the thread siblings to cpu X in the same core;
+4) /sys/devices/system/cpu/cpuX/topology/core_siblings:
+represent the thread siblings to cpu X in the same physical package;
+
+To implement it in an architecture-neutral way, a new source file,
+driver/base/topology.c, is to export the 5 attributes.
+
+If one architecture wants to support this feature, it just needs to
+implement 4 defines, typically in file include/asm-XXX/topology.h.
+The 4 defines are:
+#define topology_physical_package_id(cpu)
+#define topology_core_id(cpu)
+#define topology_thread_siblings(cpu)
+#define topology_core_siblings(cpu)
+
+The type of **_id is int.
+The type of siblings is cpumask_t.
+
+To be consistent on all architectures, the 4 attributes should have
+deafult values if their values are unavailable. Below is the rule.
+1) physical_package_id: If cpu has no physical package id, -1 is the
+default value.
+2) core_id: If cpu doesn't support multi-core, its core id is 0.
+3) thread_siblings: Just include itself, if the cpu doesn't support
+HT/multi-thread.
+4) core_siblings: Just include itself, if the cpu doesn't support
+multi-core and HT/Multi-thread.
+
+So be careful when declaring the 4 defines in include/asm-XXX/topology.h.
+
+If an attribute isn't defined on an architecture, it won't be exported.
+
diff --git a/Documentation/driver-model/overview.txt b/Documentation/driver-model/overview.txt
index 44662735cf8..ac4a7a737e4 100644
--- a/Documentation/driver-model/overview.txt
+++ b/Documentation/driver-model/overview.txt
@@ -1,50 +1,43 @@
The Linux Kernel Device Model
-Patrick Mochel <mochel@osdl.org>
+Patrick Mochel <mochel@digitalimplant.org>
-26 August 2002
+Drafted 26 August 2002
+Updated 31 January 2006
Overview
~~~~~~~~
-This driver model is a unification of all the current, disparate driver models
-that are currently in the kernel. It is intended to augment the
+The Linux Kernel Driver Model is a unification of all the disparate driver
+models that were previously used in the kernel. It is intended to augment the
bus-specific drivers for bridges and devices by consolidating a set of data
and operations into globally accessible data structures.
-Current driver models implement some sort of tree-like structure (sometimes
-just a list) for the devices they control. But, there is no linkage between
-the different bus types.
+Traditional driver models implemented some sort of tree-like structure
+(sometimes just a list) for the devices they control. There wasn't any
+uniformity across the different bus types.
-A common data structure can provide this linkage with little overhead: when a
-bus driver discovers a particular device, it can insert it into the global
-tree as well as its local tree. In fact, the local tree becomes just a subset
-of the global tree.
-
-Common data fields can also be moved out of the local bus models into the
-global model. Some of the manipulations of these fields can also be
-consolidated. Most likely, manipulation functions will become a set
-of helper functions, which the bus drivers wrap around to include any
-bus-specific items.
-
-The common device and bridge interface currently reflects the goals of the
-modern PC: namely the ability to do seamless Plug and Play, power management,
-and hot plug. (The model dictated by Intel and Microsoft (read: ACPI) ensures
-us that any device in the system may fit any of these criteria.)
-
-In reality, not every bus will be able to support such operations. But, most
-buses will support a majority of those operations, and all future buses will.
-In other words, a bus that doesn't support an operation is the exception,
-instead of the other way around.
+The current driver model provides a comon, uniform data model for describing
+a bus and the devices that can appear under the bus. The unified bus
+model includes a set of common attributes which all busses carry, and a set
+of common callbacks, such as device discovery during bus probing, bus
+shutdown, bus power management, etc.
+The common device and bridge interface reflects the goals of the modern
+computer: namely the ability to do seamless device "plug and play", power
+management, and hot plug. In particular, the model dictated by Intel and
+Microsoft (namely ACPI) ensures that almost every device on almost any bus
+on an x86-compatible system can work within this paradigm. Of course,
+not every bus is able to support all such operations, although most
+buses support a most of those operations.
Downstream Access
~~~~~~~~~~~~~~~~~
Common data fields have been moved out of individual bus layers into a common
-data structure. But, these fields must still be accessed by the bus layers,
+data structure. These fields must still be accessed by the bus layers,
and sometimes by the device-specific drivers.
Other bus layers are encouraged to do what has been done for the PCI layer.
@@ -53,7 +46,7 @@ struct pci_dev now looks like this:
struct pci_dev {
...
- struct device device;
+ struct device dev;
};
Note first that it is statically allocated. This means only one allocation on
@@ -64,9 +57,9 @@ the two.
The PCI bus layer freely accesses the fields of struct device. It knows about
the structure of struct pci_dev, and it should know the structure of struct
-device. PCI devices that have been converted generally do not touch the fields
-of struct device. More precisely, device-specific drivers should not touch
-fields of struct device unless there is a strong compelling reason to do so.
+device. Individual PCI device drivers that have been converted the the current
+driver model generally do not and should not touch the fields of struct device,
+unless there is a strong compelling reason to do so.
This abstraction is prevention of unnecessary pain during transitional phases.
If the name of the field changes or is removed, then every downstream driver
diff --git a/Documentation/filesystems/configfs/configfs_example.c b/Documentation/filesystems/configfs/configfs_example.c
index f3c6e4946f9..3d4713a6c20 100644
--- a/Documentation/filesystems/configfs/configfs_example.c
+++ b/Documentation/filesystems/configfs/configfs_example.c
@@ -320,6 +320,7 @@ static struct config_item_type simple_children_type = {
.ct_item_ops = &simple_children_item_ops,
.ct_group_ops = &simple_children_group_ops,
.ct_attrs = simple_children_attrs,
+ .ct_owner = THIS_MODULE,
};
static struct configfs_subsystem simple_children_subsys = {
@@ -403,6 +404,7 @@ static struct config_item_type group_children_type = {
.ct_item_ops = &group_children_item_ops,
.ct_group_ops = &group_children_group_ops,
.ct_attrs = group_children_attrs,
+ .ct_owner = THIS_MODULE,
};
static struct configfs_subsystem group_children_subsys = {
diff --git a/Documentation/filesystems/ocfs2.txt b/Documentation/filesystems/ocfs2.txt
index f2595caf052..4389c684a80 100644
--- a/Documentation/filesystems/ocfs2.txt
+++ b/Documentation/filesystems/ocfs2.txt
@@ -35,6 +35,7 @@ Features which OCFS2 does not support yet:
be cluster coherent.
- quotas
- cluster aware flock
+ - cluster aware lockf
- Directory change notification (F_NOTIFY)
- Distributed Caching (F_SETLEASE/F_GETLEASE/break_lease)
- POSIX ACLs
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 2b7cf19a06a..26364d06ae9 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -427,6 +427,23 @@ icmp_ignore_bogus_error_responses - BOOLEAN
will avoid log file clutter.
Default: FALSE
+icmp_errors_use_inbound_ifaddr - BOOLEAN
+
+ If zero, icmp error messages are sent with the primary address of
+ the exiting interface.
+
+ If non-zero, the message will be sent with the primary address of
+ the interface that received the packet that caused the icmp error.
+ This is the behaviour network many administrators will expect from
+ a router. And it can make debugging complicated network layouts
+ much easier.
+
+ Note that if no primary address exists for the interface selected,
+ then the primary address of the first non-loopback interface that
+ has one will be used regarldess of this setting.
+
+ Default: 0
+
igmp_max_memberships - INTEGER
Change the maximum number of multicast groups we can subscribe to.
Default: 20
diff --git a/Documentation/parport-lowlevel.txt b/Documentation/parport-lowlevel.txt
index 1d40008a192..8f2302415ef 100644
--- a/Documentation/parport-lowlevel.txt
+++ b/Documentation/parport-lowlevel.txt
@@ -1068,7 +1068,7 @@ SYNOPSIS
struct parport_operations {
...
- void (*write_status) (struct parport *port, unsigned char s);
+ void (*write_control) (struct parport *port, unsigned char s);
...
};
@@ -1097,9 +1097,9 @@ SYNOPSIS
struct parport_operations {
...
- void (*frob_control) (struct parport *port,
- unsigned char mask,
- unsigned char val);
+ unsigned char (*frob_control) (struct parport *port,
+ unsigned char mask,
+ unsigned char val);
...
};
diff --git a/Documentation/pci-error-recovery.txt b/Documentation/pci-error-recovery.txt
index d089967e494..634d3e5b575 100644
--- a/Documentation/pci-error-recovery.txt
+++ b/Documentation/pci-error-recovery.txt
@@ -1,246 +1,396 @@
PCI Error Recovery
------------------
- May 31, 2005
-
- Current document maintainer:
- Linas Vepstas <linas@austin.ibm.com>
-
-
-Some PCI bus controllers are able to detect certain "hard" PCI errors
-on the bus, such as parity errors on the data and address busses, as
-well as SERR and PERR errors. These chipsets are then able to disable
-I/O to/from the affected device, so that, for example, a bad DMA
-address doesn't end up corrupting system memory. These same chipsets
-are also able to reset the affected PCI device, and return it to
-working condition. This document describes a generic API form
-performing error recovery.
-
-The core idea is that after a PCI error has been detected, there must
-be a way for the kernel to coordinate with all affected device drivers
-so that the pci card can be made operational again, possibly after
-performing a full electrical #RST of the PCI card. The API below
-provides a generic API for device drivers to be notified of PCI
-errors, and to be notified of, and respond to, a reset sequence.
-
-Preliminary sketch of API, cut-n-pasted-n-modified email from
-Ben Herrenschmidt, circa 5 april 2005
+ February 2, 2006
+
+ Current document maintainer:
+ Linas Vepstas <linas@austin.ibm.com>
+
+
+Many PCI bus controllers are able to detect a variety of hardware
+PCI errors on the bus, such as parity errors on the data and address
+busses, as well as SERR and PERR errors. Some of the more advanced
+chipsets are able to deal with these errors; these include PCI-E chipsets,
+and the PCI-host bridges found on IBM Power4 and Power5-based pSeries
+boxes. A typical action taken is to disconnect the affected device,
+halting all I/O to it. The goal of a disconnection is to avoid system
+corruption; for example, to halt system memory corruption due to DMA's
+to "wild" addresses. Typically, a reconnection mechanism is also
+offered, so that the affected PCI device(s) are reset and put back
+into working condition. The reset phase requires coordination
+between the affected device drivers and the PCI controller chip.
+This document describes a generic API for notifying device drivers
+of a bus disconnection, and then performing error recovery.
+This API is currently implemented in the 2.6.16 and later kernels.
+
+Reporting and recovery is performed in several steps. First, when
+a PCI hardware error has resulted in a bus disconnect, that event
+is reported as soon as possible to all affected device drivers,
+including multiple instances of a device driver on multi-function
+cards. This allows device drivers to avoid deadlocking in spinloops,
+waiting for some i/o-space register to change, when it never will.
+It also gives the drivers a chance to defer incoming I/O as
+needed.
+
+Next, recovery is performed in several stages. Most of the complexity
+is forced by the need to handle multi-function devices, that is,
+devices that have multiple device drivers associated with them.
+In the first stage, each driver is allowed to indicate what type
+of reset it desires, the choices being a simple re-enabling of I/O
+or requesting a hard reset (a full electrical #RST of the PCI card).
+If any driver requests a full reset, that is what will be done.
+
+After a full reset and/or a re-enabling of I/O, all drivers are
+again notified, so that they may then perform any device setup/config
+that may be required. After these have all completed, a final
+"resume normal operations" event is sent out.
+
+The biggest reason for choosing a kernel-based implementation rather
+than a user-space implementation was the need to deal with bus
+disconnects of PCI devices attached to storage media, and, in particular,
+disconnects from devices holding the root file system. If the root
+file system is disconnected, a user-space mechanism would have to go
+through a large number of contortions to complete recovery. Almost all
+of the current Linux file systems are not tolerant of disconnection
+from/reconnection to their underlying block device. By contrast,
+bus errors are easy to manage in the device driver. Indeed, most
+device drivers already handle very similar recovery procedures;
+for example, the SCSI-generic layer already provides significant
+mechanisms for dealing with SCSI bus errors and SCSI bus resets.
+
+
+Detailed Design
+---------------
+Design and implementation details below, based on a chain of
+public email discussions with Ben Herrenschmidt, circa 5 April 2005.
The error recovery API support is exposed to the driver in the form of
a structure of function pointers pointed to by a new field in struct
-pci_driver. The absence of this pointer in pci_driver denotes an
-"non-aware" driver, behaviour on these is platform dependant.
-Platforms like ppc64 can try to simulate pci hotplug remove/add.
-
-The definition of "pci_error_token" is not covered here. It is based on
-Seto's work on the synchronous error detection. We still need to define
-functions for extracting infos out of an opaque error token. This is
-separate from this API.
+pci_driver. A driver that fails to provide the structure is "non-aware",
+and the actual recovery steps taken are platform dependent. The
+arch/powerpc implementation will simulate a PCI hotplug remove/add.
This structure has the form:
-
struct pci_error_handlers
{
- int (*error_detected)(struct pci_dev *dev, pci_error_token error);
+ int (*error_detected)(struct pci_dev *dev, enum pci_channel_state);
int (*mmio_enabled)(struct pci_dev *dev);
- int (*resume)(struct pci_dev *dev);
int (*link_reset)(struct pci_dev *dev);
int (*slot_reset)(struct pci_dev *dev);
+ void (*resume)(struct pci_dev *dev);
};
-A driver doesn't have to implement all of these callbacks. The
-only mandatory one is error_detected(). If a callback is not
-implemented, the corresponding feature is considered unsupported.
-For example, if mmio_enabled() and resume() aren't there, then the
-driver is assumed as not doing any direct recovery and requires
+The possible channel states are:
+enum pci_channel_state {
+ pci_channel_io_normal, /* I/O channel is in normal state */
+ pci_channel_io_frozen, /* I/O to channel is blocked */
+ pci_channel_io_perm_failure, /* PCI card is dead */
+};
+
+Possible return values are:
+enum pci_ers_result {
+ PCI_ERS_RESULT_NONE, /* no result/none/not supported in device driver */
+ PCI_ERS_RESULT_CAN_RECOVER, /* Device driver can recover without slot reset */
+ PCI_ERS_RESULT_NEED_RESET, /* Device driver wants slot to be reset. */
+ PCI_ERS_RESULT_DISCONNECT, /* Device has completely failed, is unrecoverable */
+ PCI_ERS_RESULT_RECOVERED, /* Device driver is fully recovered and operational */
+};
+
+A driver does not have to implement all of these callbacks; however,
+if it implements any, it must implement error_detected(). If a callback
+is not implemented, the corresponding feature is considered unsupported.
+For example, if mmio_enabled() and resume() aren't there, then it
+is assumed that the driver is not doing any direct recovery and requires
a reset. If link_reset() is not implemented, the card is assumed as
-not caring about link resets, in which case, if recover is supported,
-the core can try recover (but not slot_reset() unless it really did
-reset the slot). If slot_reset() is not supported, link_reset() can
-be called instead on a slot reset.
-
-At first, the call will always be :
-
- 1) error_detected()
-
- Error detected. This is sent once after an error has been detected. At
-this point, the device might not be accessible anymore depending on the
-platform (the slot will be isolated on ppc64). The driver may already
-have "noticed" the error because of a failing IO, but this is the proper
-"synchronisation point", that is, it gives a chance to the driver to
-cleanup, waiting for pending stuff (timers, whatever, etc...) to
-complete; it can take semaphores, schedule, etc... everything but touch
-the device. Within this function and after it returns, the driver
+not care about link resets. Typically a driver will want to know about
+a slot_reset().
+
+The actual steps taken by a platform to recover from a PCI error
+event will be platform-dependent, but will follow the general
+sequence described below.
+
+STEP 0: Error Event
+-------------------
+PCI bus error is detect by the PCI hardware. On powerpc, the slot
+is isolated, in that all I/O is blocked: all reads return 0xffffffff,
+all writes are ignored.
+
+
+STEP 1: Notification
+--------------------
+Platform calls the error_detected() callback on every instance of
+every driver affected by the error.
+
+At this point, the device might not be accessible anymore, depending on
+the platform (the slot will be isolated on powerpc). The driver may
+already have "noticed" the error because of a failing I/O, but this
+is the proper "synchronization point", that is, it gives the driver
+a chance to cleanup, waiting for pending stuff (timers, whatever, etc...)
+to complete; it can take semaphores, schedule, etc... everything but
+touch the device. Within this function and after it returns, the driver
shouldn't do any new IOs. Called in task context. This is sort of a
"quiesce" point. See note about interrupts at the end of this doc.
- Result codes:
- - PCIERR_RESULT_CAN_RECOVER:
- Driever returns this if it thinks it might be able to recover
+All drivers participating in this system must implement this call.
+The driver must return one of the following result codes:
+ - PCI_ERS_RESULT_CAN_RECOVER:
+ Driver returns this if it thinks it might be able to recover
the HW by just banging IOs or if it wants to be given
- a chance to extract some diagnostic informations (see
- below).
- - PCIERR_RESULT_NEED_RESET:
- Driver returns this if it thinks it can't recover unless the
- slot is reset.
- - PCIERR_RESULT_DISCONNECT:
- Return this if driver thinks it won't recover at all,
- (this will detach the driver ? or just leave it
- dangling ? to be decided)
-
-So at this point, we have called error_detected() for all drivers
-on the segment that had the error. On ppc64, the slot is isolated. What
-happens now typically depends on the result from the drivers. If all
-drivers on the segment/slot return PCIERR_RESULT_CAN_RECOVER, we would
-re-enable IOs on the slot (or do nothing special if the platform doesn't
-isolate slots) and call 2). If not and we can reset slots, we go to 4),
-if neither, we have a dead slot. If it's an hotplug slot, we might
-"simulate" reset by triggering HW unplug/replug though.
-
->>> Current ppc64 implementation assumes that a device driver will
->>> *not* schedule or semaphore in this routine; the current ppc64
+ a chance to extract some diagnostic information (see
+ mmio_enable, below).
+ - PCI_ERS_RESULT_NEED_RESET:
+ Driver returns this if it can't recover without a hard
+ slot reset.
+ - PCI_ERS_RESULT_DISCONNECT:
+ Driver returns this if it doesn't want to recover at all.
+
+The next step taken will depend on the result codes returned by the
+drivers.
+
+If all drivers on the segment/slot return PCI_ERS_RESULT_CAN_RECOVER,
+then the platform should re-enable IOs on the slot (or do nothing in
+particular, if the platform doesn't isolate slots), and recovery
+proceeds to STEP 2 (MMIO Enable).
+
+If any driver requested a slot reset (by returning PCI_ERS_RESULT_NEED_RESET),
+then recovery proceeds to STEP 4 (Slot Reset).
+
+If the platform is unable to recover the slot, the next step
+is STEP 6 (Permanent Failure).
+
+>>> The current powerpc implementation assumes that a device driver will
+>>> *not* schedule or semaphore in this routine; the current powerpc
>>> implementation uses one kernel thread to notify all devices;
->>> thus, of one device sleeps/schedules, all devices are affected.
+>>> thus, if one device sleeps/schedules, all devices are affected.
>>> Doing better requires complex multi-threaded logic in the error
>>> recovery implementation (e.g. waiting for all notification threads
>>> to "join" before proceeding with recovery.) This seems excessively
>>> complex and not worth implementing.
->>> The current ppc64 implementation doesn't much care if the device
->>> attempts i/o at this point, or not. I/O's will fail, returning
+>>> The current powerpc implementation doesn't much care if the device
+>>> attempts I/O at this point, or not. I/O's will fail, returning
>>> a value of 0xff on read, and writes will be dropped. If the device
>>> driver attempts more than 10K I/O's to a frozen adapter, it will
>>> assume that the device driver has gone into an infinite loop, and
->>> it will panic the the kernel.
+>>> it will panic the the kernel. There doesn't seem to be any other
+>>> way of stopping a device driver that insists on spinning on I/O.
- 2) mmio_enabled()
+STEP 2: MMIO Enabled
+-------------------
+The platform re-enables MMIO to the device (but typically not the
+DMA), and then calls the mmio_enabled() callback on all affected
+device drivers.
- This is the "early recovery" call. IOs are allowed again, but DMA is
+This is the "early recovery" call. IOs are allowed again, but DMA is
not (hrm... to be discussed, I prefer not), with some restrictions. This
is NOT a callback for the driver to start operations again, only to
peek/poke at the device, extract diagnostic information, if any, and
eventually do things like trigger a device local reset or some such,
-but not restart operations. This is sent if all drivers on a segment
-agree that they can try to recover and no automatic link reset was
-performed by the HW. If the platform can't just re-enable IOs without
-a slot reset or a link reset, it doesn't call this callback and goes
-directly to 3) or 4). All IOs should be done _synchronously_ from
-within this callback, errors triggered by them will be returned via
-the normal pci_check_whatever() api, no new error_detected() callback
-will be issued due to an error happening here. However, such an error
-might cause IOs to be re-blocked for the whole segment, and thus
-invalidate the recovery that other devices on the same segment might
-have done, forcing the whole segment into one of the next states,
-that is link reset or slot reset.
-
- Result codes:
- - PCIERR_RESULT_RECOVERED
+but not restart operations. This is callback is made if all drivers on
+a segment agree that they can try to recover and if no automatic link reset
+was performed by the HW. If the platform can't just re-enable IOs without
+a slot reset or a link reset, it wont call this callback, and instead
+will have gone directly to STEP 3 (Link Reset) or STEP 4 (Slot Reset)
+
+>>> The following is proposed; no platform implements this yet:
+>>> Proposal: All I/O's should be done _synchronously_ from within
+>>> this callback, errors triggered by them will be returned via
+>>> the normal pci_check_whatever() API, no new error_detected()
+>>> callback will be issued due to an error happening here. However,
+>>> such an error might cause IOs to be re-blocked for the whole
+>>> segment, and thus invalidate the recovery that other devices
+>>> on the same segment might have done, forcing the whole segment
+>>> into one of the next states, that is, link reset or slot reset.
+
+The driver should return one of the following result codes:
+ - PCI_ERS_RESULT_RECOVERED
Driver returns this if it thinks the device is fully
- functionnal and thinks it is ready to start
+ functional and thinks it is ready to start
normal driver operations again. There is no
guarantee that the driver will actually be
allowed to proceed, as another driver on the
same segment might have failed and thus triggered a
slot reset on platforms that support it.
- - PCIERR_RESULT_NEED_RESET
+ - PCI_ERS_RESULT_NEED_RESET
Driver returns this if it thinks the device is not
recoverable in it's current state and it needs a slot
reset to proceed.
- - PCIERR_RESULT_DISCONNECT
+ - PCI_ERS_RESULT_DISCONNECT
Same as above. Total failure, no recovery even after
reset driver dead. (To be defined more precisely)
->>> The current ppc64 implementation does not implement this callback.
+The next step taken depends on the results returned by the drivers.
+If all drivers returned PCI_ERS_RESULT_RECOVERED, then the platform
+proceeds to either STEP3 (Link Reset) or to STEP 5 (Resume Operations).
+
+If any driver returned PCI_ERS_RESULT_NEED_RESET, then the platform
+proceeds to STEP 4 (Slot Reset)
- 3) link_reset()
+>>> The current powerpc implementation does not implement this callback.
- This is called after the link has been reset. This is typically
-a PCI Express specific state at this point and is done whenever a
-non-fatal error has been detected that can be "solved" by resetting
-the link. This call informs the driver of the reset and the driver
-should check if the device appears to be in working condition.
-This function acts a bit like 2) mmio_enabled(), in that the driver
-is not supposed to restart normal driver I/O operations right away.
-Instead, it should just "probe" the device to check it's recoverability
-status. If all is right, then the core will call resume() once all
-drivers have ack'd link_reset().
+
+STEP 3: Link Reset
+------------------
+The platform resets the link, and then calls the link_reset() callback
+on all affected device drivers. This is a PCI-Express specific state
+and is done whenever a non-fatal error has been detected that can be
+"solved" by resetting the link. This call informs the driver of the
+reset and the driver should check to see if the device appears to be
+in working condition.
+
+The driver is not supposed to restart normal driver I/O operations
+at this point. It should limit itself to "probing" the device to
+check it's recoverability status. If all is right, then the platform
+will call resume() once all drivers have ack'd link_reset().
Result codes:
- (identical to mmio_enabled)
+ (identical to STEP 3 (MMIO Enabled)
+
+The platform then proceeds to either STEP 4 (Slot Reset) or STEP 5
+(Resume Operations).
+
+>>> The current powerpc implementation does not implement this callback.
+
+
+STEP 4: Slot Reset
+------------------
+The platform performs a soft or hard reset of the device, and then
+calls the slot_reset() callback.
+
+A soft reset consists of asserting the adapter #RST line and then
+restoring the PCI BAR's and PCI configuration header to a state
+that is equivalent to what it would be after a fresh system
+power-on followed by power-on BIOS/system firmware initialization.
+If the platform supports PCI hotplug, then the reset might be
+performed by toggling the slot electrical power off/on.
->>> The current ppc64 implementation does not implement this callback.
+It is important for the platform to restore the PCI config space
+to the "fresh poweron" state, rather than the "last state". After
+a slot reset, the device driver will almost always use its standard
+device initialization routines, and an unusual config space setup
+may result in hung devices, kernel panics, or silent data corruption.
- 4) slot_reset()
+This call gives drivers the chance to re-initialize the hardware
+(re-download firmware, etc.). At this point, the driver may assume
+that he card is in a fresh state and is fully functional. In
+particular, interrupt generation should work normally.
- This is called after the slot has been soft or hard reset by the
-platform. A soft reset consists of asserting the adapter #RST line
-and then restoring the PCI BARs and PCI configuration header. If the
-platform supports PCI hotplug, then it might instead perform a hard
-reset by toggling power on the slot off/on. This call gives drivers
-the chance to re-initialize the hardware (re-download firmware, etc.),
-but drivers shouldn't restart normal I/O processing operations at
-this point. (See note about interrupts; interrupts aren't guaranteed
-to be delivered until the resume() callback has been called). If all
-device drivers report success on this callback, the patform will call
-resume() to complete the error handling and let the driver restart
-normal I/O processing.
+Drivers should not yet restart normal I/O processing operations
+at this point. If all device drivers report success on this
+callback, the platform will call resume() to complete the sequence,
+and let the driver restart normal I/O processing.
A driver can still return a critical failure for this function if
it can't get the device operational after reset. If the platform
-previously tried a soft reset, it migh now try a hard reset (power
+previously tried a soft reset, it might now try a hard reset (power
cycle) and then call slot_reset() again. It the device still can't
be recovered, there is nothing more that can be done; the platform
will typically report a "permanent failure" in such a case. The
device will be considered "dead" in this case.
- Result codes:
- - PCIERR_RESULT_DISCONNECT
- Same as above.
+Drivers for multi-function cards will need to coordinate among
+themselves as to which driver instance will perform any "one-shot"
+or global device initialization. For example, the Symbios sym53cxx2
+driver performs device init only from PCI function 0:
->>> The current ppc64 implementation does not try a power-cycle reset
->>> if the driver returned PCIERR_RESULT_DISCONNECT. However, it should.
++ if (PCI_FUNC(pdev->devfn) == 0)
++ sym_reset_scsi_bus(np, 0);
- 5) resume()
-
- This is called if all drivers on the segment have returned
-PCIERR_RESULT_RECOVERED from one of the 3 prevous callbacks.
-That basically tells the driver to restart activity, tht everything
-is back and running. No result code is taken into account here. If
-a new error happens, it will restart a new error handling process.
+ Result codes:
+ - PCI_ERS_RESULT_DISCONNECT
+ Same as above.
-That's it. I think this covers all the possibilities. The way those
-callbacks are called is platform policy. A platform with no slot reset
-capability for example may want to just "ignore" drivers that can't
+Platform proceeds either to STEP 5 (Resume Operations) or STEP 6 (Permanent
+Failure).
+
+>>> The current powerpc implementation does not currently try a
+>>> power-cycle reset if the driver returned PCI_ERS_RESULT_DISCONNECT.
+>>> However, it probably should.
+
+
+STEP 5: Resume Operations
+-------------------------
+The platform will call the resume() callback on all affected device
+drivers if all drivers on the segment have returned
+PCI_ERS_RESULT_RECOVERED from one of the 3 previous callbacks.
+The goal of this callback is to tell the driver to restart activity,
+that everything is back and running. This callback does not return
+a result code.
+
+At this point, if a new error happens, the platform will restart
+a new error recovery sequence.
+
+STEP 6: Permanent Failure
+-------------------------
+A "permanent failure" has occurred, and the platform cannot recover
+the device. The platform will call error_detected() with a
+pci_channel_state value of pci_channel_io_perm_failure.
+
+The device driver should, at this point, assume the worst. It should
+cancel all pending I/O, refuse all new I/O, returning -EIO to
+higher layers. The device driver should then clean up all of its
+memory and remove itself from kernel operations, much as it would
+during system shutdown.
+
+The platform will typically notify the system operator of the
+permanent failure in some way. If the device is hotplug-capable,
+the operator will probably want to remove and replace the device.
+Note, however, not all failures are truly "permanent". Some are
+caused by over-heating, some by a poorly seated card. Many
+PCI error events are caused by software bugs, e.g. DMA's to
+wild addresses or bogus split transactions due to programming
+errors. See the discussion in powerpc/eeh-pci-error-recovery.txt
+for additional detail on real-life experience of the causes of
+software errors.
+
+
+Conclusion; General Remarks
+---------------------------
+The way those callbacks are called is platform policy. A platform with
+no slot reset capability may want to just "ignore" drivers that can't
recover (disconnect them) and try to let other cards on the same segment
recover. Keep in mind that in most real life cases, though, there will
be only one driver per segment.
-Now, there is a note about interrupts. If you get an interrupt and your
+Now, a note about interrupts. If you get an interrupt and your
device is dead or has been isolated, there is a problem :)
-
-After much thinking, I decided to leave that to the platform. That is,
-the recovery API only precies that:
+The current policy is to turn this into a platform policy.
+That is, the recovery API only requires that:
- There is no guarantee that interrupt delivery can proceed from any
device on the segment starting from the error detection and until the
-restart callback is sent, at which point interrupts are expected to be
+resume callback is sent, at which point interrupts are expected to be
fully operational.
- - There is no guarantee that interrupt delivery is stopped, that is, ad
-river that gets an interrupts after detecting an error, or that detects
-and error within the interrupt handler such that it prevents proper
+ - There is no guarantee that interrupt delivery is stopped, that is,
+a driver that gets an interrupt after detecting an error, or that detects
+an error within the interrupt handler such that it prevents proper
ack'ing of the interrupt (and thus removal of the source) should just
-return IRQ_NOTHANDLED. It's up to the platform to deal with taht
-condition, typically by masking the irq source during the duration of
+return IRQ_NOTHANDLED. It's up to the platform to deal with that
+condition, typically by masking the IRQ source during the duration of
the error handling. It is expected that the platform "knows" which
interrupts are routed to error-management capable slots and can deal
-with temporarily disabling that irq number during error processing (this
+with temporarily disabling that IRQ number during error processing (this
isn't terribly complex). That means some IRQ latency for other devices
sharing the interrupt, but there is simply no other way. High end
platforms aren't supposed to share interrupts between many devices
anyway :)
-
-Revised: 31 May 2005 Linas Vepstas <linas@austin.ibm.com>
+>>> Implementation details for the powerpc platform are discussed in
+>>> the file Documentation/powerpc/eeh-pci-error-recovery.txt
+
+>>> As of this writing, there are six device drivers with patches
+>>> implementing error recovery. Not all of these patches are in
+>>> mainline yet. These may be used as "examples":
+>>>
+>>> drivers/scsi/ipr.c
+>>> drivers/scsi/sym53cxx_2
+>>> drivers/next/e100.c
+>>> drivers/net/e1000
+>>> drivers/net/ixgb
+>>> drivers/net/s2io.c
+
+The End
+-------
diff --git a/Documentation/x86_64/boot-options.txt b/Documentation/x86_64/boot-options.txt
index 9c5fc15d03d..153740f460a 100644
--- a/Documentation/x86_64/boot-options.txt
+++ b/Documentation/x86_64/boot-options.txt
@@ -40,6 +40,18 @@ APICs
no_timer_check Don't check the IO-APIC timer. This can work around
problems with incorrect timer initialization on some boards.
+ apicmaintimer Run time keeping from the local APIC timer instead
+ of using the PIT/HPET interrupt for this. This is useful
+ when the PIT/HPET interrupts are unreliable.
+
+ noapicmaintimer Don't do time keeping using the APIC timer.
+ Useful when this option was auto selected, but doesn't work.
+
+ apicpmtimer
+ Do APIC timer calibration using the pmtimer. Implies
+ apicmaintimer. Useful when your PIT timer is totally
+ broken.
+
Early Console
syntax: earlyprintk=vga
diff --git a/MAINTAINERS b/MAINTAINERS
index 42955fe1ffa..11d44daa602 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -557,7 +557,8 @@ S: Supported
CONFIGFS
P: Joel Becker
-M: Joel Becker <joel.becker@oracle.com>
+M: joel.becker@oracle.com
+L: linux-kernel@vger.kernel.org
S: Supported
CIRRUS LOGIC GENERIC FBDEV DRIVER
@@ -1984,7 +1985,6 @@ M: philb@gnu.org
P: Tim Waugh
M: tim@cyberelk.net
P: David Campbell
-M: campbell@torque.net
P: Andrea Arcangeli
M: andrea@suse.de
L: linux-parport@lists.infradead.org
@@ -2298,7 +2298,7 @@ S: Supported
SELINUX SECURITY MODULE
P: Stephen Smalley
-M: sds@epoch.ncsc.mil
+M: sds@tycho.nsa.gov
P: James Morris
M: jmorris@namei.org
L: linux-kernel@vger.kernel.org (kernel issues)
diff --git a/Makefile b/Makefile
index 252a659896f..cd5b619db9d 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 6
SUBLEVEL = 16
-EXTRAVERSION =-rc1
+EXTRAVERSION =-rc2
NAME=Sliding Snow Leopard
# *DOCUMENTATION*
diff --git a/arch/arm/configs/at91rm9200dk_defconfig b/arch/arm/configs/at91rm9200dk_defconfig
index 5cdd13acf8f..1fe73d19888 100644
--- a/arch/arm/configs/at91rm9200dk_defconfig
+++ b/arch/arm/configs/at91rm9200dk_defconfig
@@ -85,7 +85,6 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
# CONFIG_ARCH_CLPS711X is not set
# CONFIG_ARCH_CO285 is not set
# CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_CAMELOT is not set
# CONFIG_ARCH_FOOTBRIDGE is not set
# CONFIG_ARCH_INTEGRATOR is not set
# CONFIG_ARCH_IOP3XX is not set
diff --git a/arch/arm/configs/at91rm9200ek_defconfig b/arch/arm/configs/at91rm9200ek_defconfig
index 20838ccf1da..b7d934cdb1b 100644
--- a/arch/arm/configs/at91rm9200ek_defconfig
+++ b/arch/arm/configs/at91rm9200ek_defconfig
@@ -85,7 +85,6 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
# CONFIG_ARCH_CLPS711X is not set
# CONFIG_ARCH_CO285 is not set
# CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_CAMELOT is not set
# CONFIG_ARCH_FOOTBRIDGE is not set
# CONFIG_ARCH_INTEGRATOR is not set
# CONFIG_ARCH_IOP3XX is not set
diff --git a/arch/arm/configs/csb337_defconfig b/arch/arm/configs/csb337_defconfig
index 885a3184830..94bd9932a40 100644
--- a/arch/arm/configs/csb337_defconfig
+++ b/arch/arm/configs/csb337_defconfig
@@ -85,7 +85,6 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
# CONFIG_ARCH_CLPS711X is not set
# CONFIG_ARCH_CO285 is not set
# CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_CAMELOT is not set
# CONFIG_ARCH_FOOTBRIDGE is not set
# CONFIG_ARCH_INTEGRATOR is not set
# CONFIG_ARCH_IOP3XX is not set
diff --git a/arch/arm/configs/csb637_defconfig b/arch/arm/configs/csb637_defconfig
index 95a96a5462a..1519124c550 100644
--- a/arch/arm/configs/csb637_defconfig
+++ b/arch/arm/configs/csb637_defconfig
@@ -85,7 +85,6 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
# CONFIG_ARCH_CLPS711X is not set
# CONFIG_ARCH_CO285 is not set
# CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_CAMELOT is not set
# CONFIG_ARCH_FOOTBRIDGE is not set
# CONFIG_ARCH_INTEGRATOR is not set
# CONFIG_ARCH_IOP3XX is not set
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index b41b1efaa2c..3baa70819f2 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -44,7 +44,7 @@ unsigned int get_clk_frequency_khz( int info)
/* Read clkcfg register: it has turbo, b, half-turbo (and f) */
asm( "mrc\tp14, 0, %0, c6, c0, 0" : "=r" (clkcfg) );
- t = clkcfg & (1 << 1);
+ t = clkcfg & (1 << 0);
ht = clkcfg & (1 << 2);
b = clkcfg & (1 << 3);
diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile
index b4f1e051c76..1217bf00309 100644
--- a/arch/arm/mach-s3c2410/Makefile
+++ b/arch/arm/mach-s3c2410/Makefile
@@ -10,9 +10,13 @@ obj-m :=
obj-n :=
obj- :=
+# S3C2400 support files
+obj-$(CONFIG_CPU_S3C2400) += s3c2400-gpio.o
+
# S3C2410 support files
obj-$(CONFIG_CPU_S3C2410) += s3c2410.o
+obj-$(CONFIG_CPU_S3C2410) += s3c2410-gpio.o
obj-$(CONFIG_S3C2410_DMA) += dma.o
# Power Management support
@@ -25,6 +29,7 @@ obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o
obj-$(CONFIG_CPU_S3C2440) += s3c2440.o s3c2440-dsc.o
obj-$(CONFIG_CPU_S3C2440) += s3c2440-irq.o
obj-$(CONFIG_CPU_S3C2440) += s3c2440-clock.o
+obj-$(CONFIG_CPU_S3C2440) += s3c2410-gpio.o
# bast extras
diff --git a/arch/arm/mach-s3c2410/cpu.c b/arch/arm/mach-s3c2410/cpu.c
index 687fe371369..00a379334b6 100644
--- a/arch/arm/mach-s3c2410/cpu.c
+++ b/arch/arm/mach-s3c2410/cpu.c
@@ -40,6 +40,7 @@
#include "cpu.h"
#include "clock.h"
+#include "s3c2400.h"
#include "s3c2410.h"
#include "s3c2440.h"
@@ -55,6 +56,7 @@ struct cpu_table {
/* table of supported CPUs */
+static const char name_s3c2400[] = "S3C2400";
static const char name_s3c2410[] = "S3C2410";
static const char name_s3c2440[] = "S3C2440";
static const char name_s3c2410a[] = "S3C2410A";
@@ -96,7 +98,16 @@ static struct cpu_table cpu_ids[] __initdata = {
.init_uarts = s3c2440_init_uarts,
.init = s3c2440_init,
.name = name_s3c2440a
- }
+ },
+ {
+ .idcode = 0x0, /* S3C2400 doesn't have an idcode */
+ .idmask = 0xffffffff,
+ .map_io = s3c2400_map_io,
+ .init_clocks = s3c2400_init_clocks,
+ .init_uarts = s3c2400_init_uarts,
+ .init = s3c2400_init,
+ .name = name_s3c2400
+ },
};
/* minimal IO mapping */
@@ -148,12 +159,15 @@ static struct cpu_table *cpu;
void __init s3c24xx_init_io(struct map_desc *mach_desc, int size)
{
- unsigned long idcode;
+ unsigned long idcode = 0x0;
/* initialise the io descriptors we need for initialisation */
iotable_init(s3c_iodesc, ARRAY_SIZE(s3c_iodesc));
+#ifndef CONFIG_CPU_S3C2400
idcode = __raw_readl(S3C2410_GSTATUS1);
+#endif
+
cpu = s3c_lookup_cpu(idcode);
if (cpu == NULL) {
diff --git a/arch/arm/mach-s3c2410/gpio.c b/arch/arm/mach-s3c2410/gpio.c
index 23ea3d5fa09..cd39e868458 100644
--- a/arch/arm/mach-s3c2410/gpio.c
+++ b/arch/arm/mach-s3c2410/gpio.c
@@ -31,6 +31,7 @@
* 05-Nov-2004 BJD EXPORT_SYMBOL() added for all code
* 13-Mar-2005 BJD Updates for __iomem
* 26-Oct-2005 BJD Added generic configuration types
+ * 15-Jan-2006 LCVR Added support for the S3C2400
*/
@@ -48,7 +49,7 @@
void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function)
{
- void __iomem *base = S3C2410_GPIO_BASE(pin);
+ void __iomem *base = S3C24XX_GPIO_BASE(pin);
unsigned long mask;
unsigned long con;
unsigned long flags;
@@ -95,7 +96,7 @@ EXPORT_SYMBOL(s3c2410_gpio_cfgpin);
unsigned int s3c2410_gpio_getcfg(unsigned int pin)
{
- void __iomem *base = S3C2410_GPIO_BASE(pin);
+ void __iomem *base = S3C24XX_GPIO_BASE(pin);
unsigned long mask;
if (pin < S3C2410_GPIO_BANKB) {
@@ -111,7 +112,7 @@ EXPORT_SYMBOL(s3c2410_gpio_getcfg);
void s3c2410_gpio_pullup(unsigned int pin, unsigned int to)
{
- void __iomem *base = S3C2410_GPIO_BASE(pin);
+ void __iomem *base = S3C24XX_GPIO_BASE(pin);
unsigned long offs = S3C2410_GPIO_OFFSET(pin);
unsigned long flags;
unsigned long up;
@@ -133,7 +134,7 @@ EXPORT_SYMBOL(s3c2410_gpio_pullup);
void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)
{
- void __iomem *base = S3C2410_GPIO_BASE(pin);
+ void __iomem *base = S3C24XX_GPIO_BASE(pin);
unsigned long offs = S3C2410_GPIO_OFFSET(pin);
unsigned long flags;
unsigned long dat;
@@ -152,7 +153,7 @@ EXPORT_SYMBOL(s3c2410_gpio_setpin);
unsigned int s3c2410_gpio_getpin(unsigned int pin)
{
- void __iomem *base = S3C2410_GPIO_BASE(pin);
+ void __iomem *base = S3C24XX_GPIO_BASE(pin);
unsigned long offs = S3C2410_GPIO_OFFSET(pin);
return __raw_readl(base + 0x04) & (1<< offs);
@@ -166,70 +167,13 @@ unsigned int s3c2410_modify_misccr(unsigned int clear, unsigned int change)
unsigned long misccr;
local_irq_save(flags);
- misccr = __raw_readl(S3C2410_MISCCR);
+ misccr = __raw_readl(S3C24XX_MISCCR);
misccr &= ~clear;
misccr ^= change;
- __raw_writel(misccr, S3C2410_MISCCR);
+ __raw_writel(misccr, S3C24XX_MISCCR);
local_irq_restore(flags);
return misccr;
}
EXPORT_SYMBOL(s3c2410_modify_misccr);
-
-int s3c2410_gpio_getirq(unsigned int pin)
-{
- if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15_EINT23)
- return -1; /* not valid interrupts */
-
- if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7)
- return -1; /* not valid pin */
-
- if (pin < S3C2410_GPF4)
- return (pin - S3C2410_GPF0) + IRQ_EINT0;
-
- if (pin < S3C2410_GPG0)
- return (pin - S3C2410_GPF4) + IRQ_EINT4;
-
- return (pin - S3C2410_GPG0) + IRQ_EINT8;
-}
-
-EXPORT_SYMBOL(s3c2410_gpio_getirq);
-
-int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
- unsigned int config)
-{
- void __iomem *reg = S3C2410_EINFLT0;
- unsigned long flags;
- unsigned long val;
-
- if (pin < S3C2410_GPG8 || pin > S3C2410_GPG15)
- return -1;
-
- config &= 0xff;
-
- pin -= S3C2410_GPG8_EINT16;
- reg += pin & ~3;
-
- local_irq_save(flags);
-
- /* update filter width and clock source */
-
- val = __raw_readl(reg);
- val &= ~(0xff << ((pin & 3) * 8));
- val |= config << ((pin & 3) * 8);
- __raw_writel(val, reg);
-
- /* update filter enable */
-
- val = __raw_readl(S3C2410_EXTINT2);
- val &= ~(1 << ((pin * 4) + 3));
- val |= on << ((pin * 4) + 3);
- __raw_writel(val, S3C2410_EXTINT2);
-
- local_irq_restore(flags);
-
- return 0;
-}
-
-EXPORT_SYMBOL(s3c2410_gpio_irqfilter);
diff --git a/arch/arm/mach-s3c2410/s3c2400-gpio.c b/arch/arm/mach-s3c2410/s3c2400-gpio.c
new file mode 100644
index 00000000000..5127f39fa9b
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2400-gpio.c
@@ -0,0 +1,45 @@
+/* linux/arch/arm/mach-s3c2410/gpio.c
+ *
+ * Copyright (c) 2006 Lucas Correia Villa Real <lucasvr@gobolinux.org>
+ *
+ * S3C2400 GPIO support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Changelog
+ * 15-Jan-2006 LCVR Splitted from gpio.c, adding support for the S3C2400
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/arch/regs-gpio.h>
+
+int s3c2400_gpio_getirq(unsigned int pin)
+{
+ if (pin < S3C2410_GPE0 || pin > S3C2400_GPE7_EINT7)
+ return -1; /* not valid interrupts */
+
+ return (pin - S3C2410_GPE0) + IRQ_EINT0;
+}
+
+EXPORT_SYMBOL(s3c2400_gpio_getirq);
diff --git a/arch/arm/mach-s3c2410/s3c2410-gpio.c b/arch/arm/mach-s3c2410/s3c2410-gpio.c
new file mode 100644
index 00000000000..d5e1caea1d2
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2410-gpio.c
@@ -0,0 +1,93 @@
+/* linux/arch/arm/mach-s3c2410/gpio.c
+ *
+ * Copyright (c) 2004-2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C2410 GPIO support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Changelog
+ * 15-Jan-2006 LCVR Splitted from gpio.c
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/arch/regs-gpio.h>
+
+int s3c2410_gpio_irqfilter(unsigned int pin, unsigned int on,
+ unsigned int config)
+{
+ void __iomem *reg = S3C2410_EINFLT0;
+ unsigned long flags;
+ unsigned long val;
+
+ if (pin < S3C2410_GPG8 || pin > S3C2410_GPG15)
+ return -1;
+
+ config &= 0xff;
+
+ pin -= S3C2410_GPG8_EINT16;
+ reg += pin & ~3;
+
+ local_irq_save(flags);
+
+ /* update filter width and clock source */
+
+ val = __raw_readl(reg);
+ val &= ~(0xff << ((pin & 3) * 8));
+ val |= config << ((pin & 3) * 8);
+ __raw_writel(val, reg);
+
+ /* update filter enable */
+
+ val = __raw_readl(S3C2410_EXTINT2);
+ val &= ~(1 << ((pin * 4) + 3));
+ val |= on << ((pin * 4) + 3);
+ __raw_writel(val, S3C2410_EXTINT2);
+
+ local_irq_restore(flags);
+
+ return 0;
+}
+
+EXPORT_SYMBOL(s3c2410_gpio_irqfilter);
+
+int s3c2410_gpio_getirq(unsigned int pin)
+{
+ if (pin < S3C2410_GPF0 || pin > S3C2410_GPG15_EINT23)
+ return -1; /* not valid interrupts */
+
+ if (pin < S3C2410_GPG0 && pin > S3C2410_GPF7)
+ return -1; /* not valid pin */
+
+ if (pin < S3C2410_GPF4)
+ return (pin - S3C2410_GPF0) + IRQ_EINT0;
+
+ if (pin < S3C2410_GPG0)
+ return (pin - S3C2410_GPF4) + IRQ_EINT4;
+
+ return (pin - S3C2410_GPG0) + IRQ_EINT8;
+}
+
+EXPORT_SYMBOL(s3c2410_gpio_getirq);
diff --git a/arch/arm/mach-s3c2410/sleep.S b/arch/arm/mach-s3c2410/sleep.S
index e9a055b779b..832fb86a03b 100644
--- a/arch/arm/mach-s3c2410/sleep.S
+++ b/arch/arm/mach-s3c2410/sleep.S
@@ -72,7 +72,7 @@ ENTRY(s3c2410_cpu_suspend)
@@ prepare cpu to sleep
ldr r4, =S3C2410_REFRESH
- ldr r5, =S3C2410_MISCCR
+ ldr r5, =S3C24XX_MISCCR
ldr r6, =S3C2410_CLKCON
ldr r7, [ r4 ] @ get REFRESH (and ensure in TLB)
ldr r8, [ r5 ] @ get MISCCR (and ensure in TLB)
diff --git a/arch/arm/mm/cache-v6.S b/arch/arm/mm/cache-v6.S
index 72966d90e95..d921c1024ae 100644
--- a/arch/arm/mm/cache-v6.S
+++ b/arch/arm/mm/cache-v6.S
@@ -92,22 +92,16 @@ ENTRY(v6_coherent_kern_range)
* - the Icache does not read data from the write buffer
*/
ENTRY(v6_coherent_user_range)
- bic r0, r0, #CACHE_LINE_SIZE - 1
-1:
+
#ifdef HARVARD_CACHE
- mcr p15, 0, r0, c7, c10, 1 @ clean D line
+ bic r0, r0, #CACHE_LINE_SIZE - 1
+1: mcr p15, 0, r0, c7, c10, 1 @ clean D line
mcr p15, 0, r0, c7, c5, 1 @ invalidate I line
-#endif
- mcr p15, 0, r0, c7, c5, 7 @ invalidate BTB entry
- add r0, r0, #BTB_FLUSH_SIZE
- mcr p15, 0, r0, c7, c5, 7 @ invalidate BTB entry
- add r0, r0, #BTB_FLUSH_SIZE
- mcr p15, 0, r0, c7, c5, 7 @ invalidate BTB entry
- add r0, r0, #BTB_FLUSH_SIZE
- mcr p15, 0, r0, c7, c5, 7 @ invalidate BTB entry
- add r0, r0, #BTB_FLUSH_SIZE
+ add r0, r0, #CACHE_LINE_SIZE
cmp r0, r1
blo 1b
+#endif
+ mcr p15, 0, r0, c7, c5, 6 @ invalidate BTB
#ifdef HARVARD_CACHE
mov r0, #0
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
diff --git a/arch/arm/mm/proc-xscale.S b/arch/arm/mm/proc-xscale.S
index 861b3594728..2d3823ec315 100644
--- a/arch/arm/mm/proc-xscale.S
+++ b/arch/arm/mm/proc-xscale.S
@@ -241,7 +241,15 @@ ENTRY(xscale_flush_user_cache_range)
* it also trashes the mini I-cache used by JTAG debuggers.
*/
ENTRY(xscale_coherent_kern_range)
- /* FALLTHROUGH */
+ bic r0, r0, #CACHELINESIZE - 1
+1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
+ add r0, r0, #CACHELINESIZE
+ cmp r0, r1
+ blo 1b
+ mov r0, #0
+ mcr p15, 0, r0, c7, c5, 0 @ Invalidate I cache & BTB
+ mcr p15, 0, r0, c7, c10, 4 @ Drain Write (& Fill) Buffer
+ mov pc, lr
/*
* coherent_user_range(start, end)
@@ -252,18 +260,16 @@ ENTRY(xscale_coherent_kern_range)
*
* - start - virtual start address
* - end - virtual end address
- *
- * Note: single I-cache line invalidation isn't used here since
- * it also trashes the mini I-cache used by JTAG debuggers.
*/
ENTRY(xscale_coherent_user_range)
bic r0, r0, #CACHELINESIZE - 1
1: mcr p15, 0, r0, c7, c10, 1 @ clean D entry
+ mcr p15, 0, r0, c7, c5, 1 @ Invalidate I cache entry
add r0, r0, #CACHELINESIZE
cmp r0, r1
blo 1b
mov r0, #0
- mcr p15, 0, r0, c7, c5, 0 @ Invalidate I cache & BTB
+ mcr p15, 0, r0, c7, c5, 6 @ Invalidate BTB
mcr p15, 0, r0, c7, c10, 4 @ Drain Write (& Fill) Buffer
mov pc, lr
diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c
index 1415930ceee..6f8bc1f0e6a 100644
--- a/arch/arm/oprofile/common.c
+++ b/arch/arm/oprofile/common.c
@@ -137,8 +137,9 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
if (spec) {
init_MUTEX(&op_arm_sem);
- if (spec->init() < 0)
- return -ENODEV;
+ ret = spec->init();
+ if (ret < 0)
+ return ret;
op_arm_model = spec;
init_driverfs();
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index d86c865a7cd..0afec8566e7 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -442,6 +442,7 @@ config HIGHMEM4G
config HIGHMEM64G
bool "64GB"
+ depends on X86_CMPXCHG64
help
Select this if you have a 32-bit processor and more than 4
gigabytes of physical RAM.
diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c
index f21fa0d4482..79577f0ace9 100644
--- a/arch/i386/kernel/acpi/boot.c
+++ b/arch/i386/kernel/acpi/boot.c
@@ -248,10 +248,17 @@ acpi_parse_lapic(acpi_table_entry_header * header, const unsigned long end)
acpi_table_print_madt_entry(header);
- /* Register even disabled CPUs for cpu hotplug */
-
- x86_acpiid_to_apicid[processor->acpi_id] = processor->id;
+ /* Record local apic id only when enabled */
+ if (processor->flags.enabled)
+ x86_acpiid_to_apicid[processor->acpi_id] = processor->id;
+ /*
+ * We need to register disabled CPU as well to permit
+ * counting disabled CPUs. This allows us to size
+ * cpus_possible_map more accurately, to permit
+ * to not preallocating memory for all NR_CPUS
+ * when we use CPU hotplug.
+ */
mp_register_lapic(processor->id, /* APIC ID */
processor->flags.enabled); /* Enabled? */
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index acd3f1e34ca..98a5c23cf3d 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -75,8 +75,10 @@ void ack_bad_irq(unsigned int irq)
* holds up an irq slot - in excessive cases (when multiple
* unexpected vectors occur) that might lock up the APIC
* completely.
+ * But only ack when the APIC is enabled -AK
*/
- ack_APIC_irq();
+ if (!cpu_has_apic)
+ ack_APIC_irq();
}
void __init apic_intr_init(void)
@@ -1303,6 +1305,7 @@ int __init APIC_init_uniprocessor (void)
if (!cpu_has_apic && APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) {
printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
boot_cpu_physical_apicid);
+ clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
return -1;
}
diff --git a/arch/i386/kernel/cpu/amd.c b/arch/i386/kernel/cpu/amd.c
index 333578a4e91..0810f81f2a0 100644
--- a/arch/i386/kernel/cpu/amd.c
+++ b/arch/i386/kernel/cpu/amd.c
@@ -282,3 +282,11 @@ int __init amd_init_cpu(void)
}
//early_arch_initcall(amd_init_cpu);
+
+static int __init amd_exit_cpu(void)
+{
+ cpu_devs[X86_VENDOR_AMD] = NULL;
+ return 0;
+}
+
+late_initcall(amd_exit_cpu);
diff --git a/arch/i386/kernel/cpu/centaur.c b/arch/i386/kernel/cpu/centaur.c
index 0dd92a23d62..f52669ecb93 100644
--- a/arch/i386/kernel/cpu/centaur.c
+++ b/arch/i386/kernel/cpu/centaur.c
@@ -470,3 +470,11 @@ int __init centaur_init_cpu(void)
}
//early_arch_initcall(centaur_init_cpu);
+
+static int __init centaur_exit_cpu(void)
+{
+ cpu_devs[X86_VENDOR_CENTAUR] = NULL;
+ return 0;
+}
+
+late_initcall(centaur_exit_cpu);
diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c
index 15aee26ec2b..7eb9213734a 100644
--- a/arch/i386/kernel/cpu/common.c
+++ b/arch/i386/kernel/cpu/common.c
@@ -44,6 +44,7 @@ static void default_init(struct cpuinfo_x86 * c)
static struct cpu_dev default_cpu = {
.c_init = default_init,
+ .c_vendor = "Unknown",
};
static struct cpu_dev * this_cpu = &default_cpu;
@@ -150,6 +151,7 @@ static void __devinit get_cpu_vendor(struct cpuinfo_x86 *c, int early)
{
char *v = c->x86_vendor_id;
int i;
+ static int printed;
for (i = 0; i < X86_VENDOR_NUM; i++) {
if (cpu_devs[i]) {
@@ -159,10 +161,17 @@ static void __devinit get_cpu_vendor(struct cpuinfo_x86 *c, int early)
c->x86_vendor = i;
if (!early)
this_cpu = cpu_devs[i];
- break;
+ return;
}
}
}
+ if (!printed) {
+ printed++;
+ printk(KERN_ERR "CPU: Vendor unknown, using generic init.\n");
+ printk(KERN_ERR "CPU: Your system may be unstable.\n");
+ }
+ c->x86_vendor = X86_VENDOR_UNKNOWN;
+ this_cpu = &default_cpu;
}
diff --git a/arch/i386/kernel/cpu/cyrix.c b/arch/i386/kernel/cpu/cyrix.c
index 75015975d03..00f2e058797 100644
--- a/arch/i386/kernel/cpu/cyrix.c
+++ b/arch/i386/kernel/cpu/cyrix.c
@@ -345,7 +345,7 @@ static void __init init_cyrix(struct cpuinfo_x86 *c)
/*
* Handle National Semiconductor branded processors
*/
-static void __devinit init_nsc(struct cpuinfo_x86 *c)
+static void __init init_nsc(struct cpuinfo_x86 *c)
{
/* There may be GX1 processors in the wild that are branded
* NSC and not Cyrix.
@@ -444,6 +444,14 @@ int __init cyrix_init_cpu(void)
//early_arch_initcall(cyrix_init_cpu);
+static int __init cyrix_exit_cpu(void)
+{
+ cpu_devs[X86_VENDOR_CYRIX] = NULL;
+ return 0;
+}
+
+late_initcall(cyrix_exit_cpu);
+
static struct cpu_dev nsc_cpu_dev __initdata = {
.c_vendor = "NSC",
.c_ident = { "Geode by NSC" },
@@ -458,3 +466,11 @@ int __init nsc_init_cpu(void)
}
//early_arch_initcall(nsc_init_cpu);
+
+static int __init nsc_exit_cpu(void)
+{
+ cpu_devs[X86_VENDOR_NSC] = NULL;
+ return 0;
+}
+
+late_initcall(nsc_exit_cpu);
diff --git a/arch/i386/kernel/cpu/intel_cacheinfo.c b/arch/i386/kernel/cpu/intel_cacheinfo.c
index af591c73345..ffe58cee0c4 100644
--- a/arch/i386/kernel/cpu/intel_cacheinfo.c
+++ b/arch/i386/kernel/cpu/intel_cacheinfo.c
@@ -152,6 +152,7 @@ static int __cpuinit cpuid4_cache_lookup(int index, struct _cpuid4_info *this_le
return 0;
}
+/* will only be called once; __init is safe here */
static int __init find_num_cache_leaves(void)
{
unsigned int eax, ebx, ecx, edx;
diff --git a/arch/i386/kernel/cpu/nexgen.c b/arch/i386/kernel/cpu/nexgen.c
index 30898a260a5..ad87fa58058 100644
--- a/arch/i386/kernel/cpu/nexgen.c
+++ b/arch/i386/kernel/cpu/nexgen.c
@@ -61,3 +61,11 @@ int __init nexgen_init_cpu(void)
}
//early_arch_initcall(nexgen_init_cpu);
+
+static int __init nexgen_exit_cpu(void)
+{
+ cpu_devs[X86_VENDOR_NEXGEN] = NULL;
+ return 0;
+}
+
+late_initcall(nexgen_exit_cpu);
diff --git a/arch/i386/kernel/cpu/rise.c b/arch/i386/kernel/cpu/rise.c
index 8602425628c..d08d5a2811c 100644
--- a/arch/i386/kernel/cpu/rise.c
+++ b/arch/i386/kernel/cpu/rise.c
@@ -51,3 +51,11 @@ int __init rise_init_cpu(void)
}
//early_arch_initcall(rise_init_cpu);
+
+static int __init rise_exit_cpu(void)
+{
+ cpu_devs[X86_VENDOR_RISE] = NULL;
+ return 0;
+}
+
+late_initcall(rise_exit_cpu);
diff --git a/arch/i386/kernel/cpu/transmeta.c b/arch/i386/kernel/cpu/transmeta.c
index fc426380366..bdbeb77f4e2 100644
--- a/arch/i386/kernel/cpu/transmeta.c
+++ b/arch/i386/kernel/cpu/transmeta.c
@@ -84,7 +84,7 @@ static void __init init_transmeta(struct cpuinfo_x86 *c)
#endif
}
-static void transmeta_identify(struct cpuinfo_x86 * c)
+static void __init transmeta_identify(struct cpuinfo_x86 * c)
{
u32 xlvl;
generic_identify(c);
@@ -111,3 +111,11 @@ int __init transmeta_init_cpu(void)
}
//early_arch_initcall(transmeta_init_cpu);
+
+static int __init transmeta_exit_cpu(void)
+{
+ cpu_devs[X86_VENDOR_TRANSMETA] = NULL;
+ return 0;
+}
+
+late_initcall(transmeta_exit_cpu);
diff --git a/arch/i386/kernel/cpu/umc.c b/arch/i386/kernel/cpu/umc.c
index 264fcad559d..2cd988f6dc5 100644
--- a/arch/i386/kernel/cpu/umc.c
+++ b/arch/i386/kernel/cpu/umc.c
@@ -31,3 +31,11 @@ int __init umc_init_cpu(void)
}
//early_arch_initcall(umc_init_cpu);
+
+static int __init umc_exit_cpu(void)
+{
+ cpu_devs[X86_VENDOR_UMC] = NULL;
+ return 0;
+}
+
+late_initcall(umc_exit_cpu);
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c
index d661703ac1c..63f39a7e2c9 100644
--- a/arch/i386/kernel/nmi.c
+++ b/arch/i386/kernel/nmi.c
@@ -138,7 +138,7 @@ static int __init check_nmi_watchdog(void)
if (nmi_watchdog == NMI_LOCAL_APIC)
smp_call_function(nmi_cpu_busy, (void *)&endflag, 0, 0);
- for (cpu = 0; cpu < NR_CPUS; cpu++)
+ for_each_cpu(cpu)
prev_nmi_count[cpu] = per_cpu(irq_stat, cpu).__nmi_count;
local_irq_enable();
mdelay((10*1000)/nmi_hz); // wait 10 ticks
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index 2185377fdde..0480454ebff 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -297,8 +297,10 @@ void show_regs(struct pt_regs * regs)
if (user_mode(regs))
printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp);
- printk(" EFLAGS: %08lx %s (%s)\n",
- regs->eflags, print_tainted(), system_utsname.release);
+ printk(" EFLAGS: %08lx %s (%s %.*s)\n",
+ regs->eflags, print_tainted(), system_utsname.release,
+ (int)strcspn(system_utsname.version, " "),
+ system_utsname.version);
printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n",
regs->eax,regs->ebx,regs->ecx,regs->edx);
printk("ESI: %08lx EDI: %08lx EBP: %08lx",
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index 0aaebf3e1cf..b814dbdcc91 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -166,7 +166,8 @@ static void show_trace_log_lvl(struct task_struct *task,
stack = (unsigned long*)context->previous_esp;
if (!stack)
break;
- printk(KERN_EMERG " =======================\n");
+ printk(log_lvl);
+ printk(" =======================\n");
}
}
@@ -239,9 +240,11 @@ void show_registers(struct pt_regs *regs)
}
print_modules();
printk(KERN_EMERG "CPU: %d\nEIP: %04x:[<%08lx>] %s VLI\n"
- "EFLAGS: %08lx (%s) \n",
+ "EFLAGS: %08lx (%s %.*s) \n",
smp_processor_id(), 0xffff & regs->xcs, regs->eip,
- print_tainted(), regs->eflags, system_utsname.release);
+ print_tainted(), regs->eflags, system_utsname.release,
+ (int)strcspn(system_utsname.version, " "),
+ system_utsname.version);
print_symbol(KERN_EMERG "EIP is at %s\n", regs->eip);
printk(KERN_EMERG "eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n",
regs->eax, regs->ebx, regs->ecx, regs->edx);
diff --git a/arch/i386/oprofile/backtrace.c b/arch/i386/oprofile/backtrace.c
index 21654be3f73..acc18138fb2 100644
--- a/arch/i386/oprofile/backtrace.c
+++ b/arch/i386/oprofile/backtrace.c
@@ -49,7 +49,9 @@ dump_backtrace(struct frame_head * head)
* | stack |
* --------------- saved regs->ebp value if valid (frame_head address)
* . .
- * --------------- struct pt_regs stored on stack (struct pt_regs *)
+ * --------------- saved regs->rsp value if x86_64
+ * | |
+ * --------------- struct pt_regs * stored on stack if 32-bit
* | |
* . .
* | |
@@ -57,13 +59,26 @@ dump_backtrace(struct frame_head * head)
* | |
* | | \/ Lower addresses
*
- * Thus, &pt_regs <-> stack base restricts the valid(ish) ebp values
+ * Thus, regs (or regs->rsp for x86_64) <-> stack base restricts the
+ * valid(ish) ebp values. Note: (1) for x86_64, NMI and several other
+ * exceptions use special stacks, maintained by the interrupt stack table
+ * (IST). These stacks are set up in trap_init() in
+ * arch/x86_64/kernel/traps.c. Thus, for x86_64, regs now does not point
+ * to the kernel stack; instead, it points to some location on the NMI
+ * stack. On the other hand, regs->rsp is the stack pointer saved when the
+ * NMI occurred. (2) For 32-bit, regs->esp is not valid because the
+ * processor does not save %esp on the kernel stack when interrupts occur
+ * in the kernel mode.
*/
#ifdef CONFIG_FRAME_POINTER
static int valid_kernel_stack(struct frame_head * head, struct pt_regs * regs)
{
unsigned long headaddr = (unsigned long)head;
+#ifdef CONFIG_X86_64
+ unsigned long stack = (unsigned long)regs->rsp;
+#else
unsigned long stack = (unsigned long)regs;
+#endif
unsigned long stack_base = (stack & ~(THREAD_SIZE - 1)) + THREAD_SIZE;
return headaddr > stack && headaddr < stack_base;
diff --git a/arch/ia64/kernel/topology.c b/arch/ia64/kernel/topology.c
index 706b7734e19..6e5eea19fa6 100644
--- a/arch/ia64/kernel/topology.c
+++ b/arch/ia64/kernel/topology.c
@@ -71,31 +71,33 @@ static int __init topology_init(void)
int i, err = 0;
#ifdef CONFIG_NUMA
- sysfs_nodes = kmalloc(sizeof(struct node) * MAX_NUMNODES, GFP_KERNEL);
+ sysfs_nodes = kzalloc(sizeof(struct node) * MAX_NUMNODES, GFP_KERNEL);
if (!sysfs_nodes) {
err = -ENOMEM;
goto out;
}
- memset(sysfs_nodes, 0, sizeof(struct node) * MAX_NUMNODES);
- /* MCD - Do we want to register all ONLINE nodes, or all POSSIBLE nodes? */
- for_each_online_node(i)
+ /*
+ * MCD - Do we want to register all ONLINE nodes, or all POSSIBLE nodes?
+ */
+ for_each_online_node(i) {
if ((err = register_node(&sysfs_nodes[i], i, 0)))
goto out;
+ }
#endif
- sysfs_cpus = kmalloc(sizeof(struct ia64_cpu) * NR_CPUS, GFP_KERNEL);
+ sysfs_cpus = kzalloc(sizeof(struct ia64_cpu) * NR_CPUS, GFP_KERNEL);
if (!sysfs_cpus) {
err = -ENOMEM;
goto out;
}
- memset(sysfs_cpus, 0, sizeof(struct ia64_cpu) * NR_CPUS);
- for_each_present_cpu(i)
+ for_each_present_cpu(i) {
if((err = arch_register_cpu(i)))
goto out;
+ }
out:
return err;
}
-__initcall(topology_init);
+subsys_initcall(topology_init);
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index e77a06e9621..7c914a4c67c 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -149,14 +149,20 @@ config HOTPLUG_CPU
default y if SMP
select HOTPLUG
+config ARCH_SELECT_MEMORY_MODEL
+ def_bool y
+ depends on 64BIT
+
config ARCH_DISCONTIGMEM_ENABLE
- bool "Discontiguous memory support (EXPERIMENTAL)"
- depends on 64BIT && EXPERIMENTAL
- help
- Say Y to support efficient handling of discontiguous physical memory,
- for architectures which are either NUMA (Non-Uniform Memory Access)
- or have huge holes in the physical address space for other reasons.
- See <file:Documentation/vm/numa> for more.
+ def_bool y
+ depends on 64BIT
+
+config ARCH_FLATMEM_ENABLE
+ def_bool y
+
+config ARCH_DISCONTIGMEM_DEFAULT
+ def_bool y
+ depends on ARCH_DISCONTIGMEM_ENABLE
source "kernel/Kconfig.hz"
source "mm/Kconfig"
diff --git a/arch/parisc/Kconfig.debug b/arch/parisc/Kconfig.debug
index 8caaed187a1..9166bd11726 100644
--- a/arch/parisc/Kconfig.debug
+++ b/arch/parisc/Kconfig.debug
@@ -11,4 +11,14 @@ config DEBUG_RWLOCK
too many attempts. If you suspect a rwlock problem or a kernel
hacker asks for this option then say Y. Otherwise say N.
+config DEBUG_RODATA
+ bool "Write protect kernel read-only data structures"
+ depends on DEBUG_KERNEL
+ help
+ Mark the kernel read-only data as write-protected in the pagetables,
+ in order to catch accidental (and incorrect) writes to such const
+ data. This option may have a slight performance impact because a
+ portion of the kernel code won't be covered by a TLB anymore.
+ If in doubt, say "N".
+
endmenu
diff --git a/arch/parisc/configs/b180_defconfig b/arch/parisc/configs/b180_defconfig
index 8819e7e6ae3..37e98241ce4 100644
--- a/arch/parisc/configs/b180_defconfig
+++ b/arch/parisc/configs/b180_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.14-rc5-pa1
-# Fri Oct 21 23:06:10 2005
+# Linux kernel version: 2.6.16-rc1-pa0
+# Tue Jan 17 08:21:01 2006
#
CONFIG_PARISC=y
CONFIG_MMU=y
@@ -29,8 +29,6 @@ CONFIG_SYSVIPC=y
# CONFIG_BSD_PROCESS_ACCT is not set
CONFIG_SYSCTL=y
# CONFIG_AUDIT is not set
-# CONFIG_HOTPLUG is not set
-CONFIG_KOBJECT_UEVENT=y
CONFIG_IKCONFIG=y
CONFIG_IKCONFIG_PROC=y
CONFIG_INITRAMFS_SOURCE=""
@@ -38,8 +36,10 @@ CONFIG_INITRAMFS_SOURCE=""
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
CONFIG_PRINTK=y
CONFIG_BUG=y
+CONFIG_ELF_CORE=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
@@ -48,8 +48,10 @@ CONFIG_CC_ALIGN_FUNCTIONS=0
CONFIG_CC_ALIGN_LABELS=0
CONFIG_CC_ALIGN_LOOPS=0
CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_SLAB=y
# CONFIG_TINY_SHMEM is not set
CONFIG_BASE_SMALL=0
+# CONFIG_SLOB is not set
#
# Loadable module support
@@ -57,10 +59,28 @@ CONFIG_BASE_SMALL=0
CONFIG_MODULES=y
# CONFIG_MODULE_UNLOAD is not set
CONFIG_OBSOLETE_MODPARM=y
+CONFIG_MODVERSIONS=y
# CONFIG_MODULE_SRCVERSION_ALL is not set
# CONFIG_KMOD is not set
#
+# Block layer
+#
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+
+#
# Processor type and features
#
# CONFIG_PA7000 is not set
@@ -77,6 +97,7 @@ CONFIG_HZ=250
CONFIG_FLATMEM=y
CONFIG_FLAT_NODE_MEM_MAP=y
# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
# CONFIG_PREEMPT is not set
# CONFIG_HPUX is not set
@@ -84,8 +105,8 @@ CONFIG_FLAT_NODE_MEM_MAP=y
# Bus options (PCI, PCMCIA, EISA, GSC, ISA)
#
CONFIG_GSC=y
-# CONFIG_HPPB is not set
-# CONFIG_IOMMU_CCIO is not set
+CONFIG_HPPB=y
+CONFIG_IOMMU_CCIO=y
CONFIG_GSC_LASI=y
CONFIG_GSC_WAX=y
CONFIG_EISA=y
@@ -165,8 +186,11 @@ CONFIG_IPV6=y
# CONFIG_LLC2 is not set
# CONFIG_IPX is not set
# CONFIG_ATALK is not set
+
+#
+# QoS and/or fair queueing
+#
# CONFIG_NET_SCHED is not set
-# CONFIG_NET_CLS_ROUTE is not set
#
# Network testing
@@ -205,6 +229,7 @@ CONFIG_STANDALONE=y
CONFIG_PARPORT=y
CONFIG_PARPORT_PC=y
# CONFIG_PARPORT_SERIAL is not set
+CONFIG_PARPORT_NOT_PC=y
CONFIG_PARPORT_GSC=y
# CONFIG_PARPORT_1284 is not set
@@ -230,14 +255,6 @@ CONFIG_BLK_DEV_RAM_COUNT=16
CONFIG_CDROM_PKTCDVD=m
CONFIG_CDROM_PKTCDVD_BUFFERS=8
# CONFIG_CDROM_PKTCDVD_WCACHE is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
CONFIG_ATA_OVER_ETH=y
#
@@ -281,6 +298,7 @@ CONFIG_SCSI_SPI_ATTRS=y
#
# SCSI low-level drivers
#
+# CONFIG_ISCSI_TCP is not set
# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
# CONFIG_SCSI_3W_9XXX is not set
# CONFIG_SCSI_ACARD is not set
@@ -313,21 +331,19 @@ CONFIG_SCSI_SYM53C8XX_2=y
CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0
CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-# CONFIG_SCSI_SYM53C8XX_IOMAPPED is not set
+CONFIG_SCSI_SYM53C8XX_MMIO=y
# CONFIG_SCSI_IPR is not set
-# CONFIG_SCSI_ZALON is not set
+CONFIG_SCSI_ZALON=y
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
+CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
+CONFIG_SCSI_NCR53C8XX_SYNC=40
+# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
# CONFIG_SCSI_PAS16 is not set
# CONFIG_SCSI_PSI240I is not set
# CONFIG_SCSI_QLOGIC_FAS is not set
# CONFIG_SCSI_QLOGIC_FC is not set
# CONFIG_SCSI_QLOGIC_1280 is not set
-CONFIG_SCSI_QLA2XXX=y
-# CONFIG_SCSI_QLA21XX is not set
-# CONFIG_SCSI_QLA22XX is not set
-# CONFIG_SCSI_QLA2300 is not set
-# CONFIG_SCSI_QLA2322 is not set
-# CONFIG_SCSI_QLA6312 is not set
-# CONFIG_SCSI_QLA24XX is not set
+# CONFIG_SCSI_QLA_FC is not set
# CONFIG_SCSI_LPFC is not set
# CONFIG_SCSI_SIM710 is not set
# CONFIG_SCSI_SYM53C416 is not set
@@ -397,7 +413,7 @@ CONFIG_NETDEVICES=y
#
CONFIG_NET_ETHERNET=y
# CONFIG_MII is not set
-# CONFIG_LASI_82596 is not set
+CONFIG_LASI_82596=y
# CONFIG_HAPPYMEAL is not set
# CONFIG_SUNGEM is not set
# CONFIG_CASSINI is not set
@@ -464,6 +480,7 @@ CONFIG_NET_RADIO=y
# Wireless 802.11b ISA/PCI cards support
#
# CONFIG_HERMES is not set
+# CONFIG_ATMEL is not set
#
# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
@@ -527,7 +544,7 @@ CONFIG_KEYBOARD_ATKBD_HP_KEYCODES=y
# CONFIG_KEYBOARD_XTKBD is not set
# CONFIG_KEYBOARD_NEWTON is not set
# CONFIG_KEYBOARD_HIL_OLD is not set
-# CONFIG_KEYBOARD_HIL is not set
+CONFIG_KEYBOARD_HIL=y
CONFIG_INPUT_MOUSE=y
CONFIG_MOUSE_PS2=y
# CONFIG_MOUSE_SERIAL is not set
@@ -535,7 +552,7 @@ CONFIG_MOUSE_PS2=y
# CONFIG_MOUSE_LOGIBM is not set
# CONFIG_MOUSE_PC110PAD is not set
# CONFIG_MOUSE_VSXXXAA is not set
-# CONFIG_MOUSE_HIL is not set
+CONFIG_MOUSE_HIL=y
# CONFIG_INPUT_JOYSTICK is not set
# CONFIG_INPUT_TOUCHSCREEN is not set
CONFIG_INPUT_MISC=y
@@ -549,7 +566,8 @@ CONFIG_SERIO=y
# CONFIG_SERIO_SERPORT is not set
# CONFIG_SERIO_PARKBD is not set
CONFIG_SERIO_GSCPS2=y
-# CONFIG_HP_SDC is not set
+CONFIG_HP_SDC=y
+CONFIG_HIL_MLC=y
# CONFIG_SERIO_PCIPS2 is not set
CONFIG_SERIO_LIBPS2=y
# CONFIG_SERIO_RAW is not set
@@ -569,6 +587,7 @@ CONFIG_HW_CONSOLE=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_NR_UARTS=13
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
CONFIG_SERIAL_8250_EXTENDED=y
CONFIG_SERIAL_8250_MANY_PORTS=y
CONFIG_SERIAL_8250_SHARE_IRQ=y
@@ -582,11 +601,10 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y
#
# Non-8250 serial port support
#
-# CONFIG_SERIAL_MUX is not set
-# CONFIG_PDC_CONSOLE is not set
+CONFIG_SERIAL_MUX=y
+CONFIG_SERIAL_MUX_CONSOLE=y
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
@@ -626,6 +644,12 @@ CONFIG_GEN_RTC=y
# CONFIG_I2C is not set
#
+# SPI support
+#
+# CONFIG_SPI is not set
+# CONFIG_SPI_MASTER is not set
+
+#
# Dallas's 1-wire bus
#
# CONFIG_W1 is not set
@@ -661,7 +685,6 @@ CONFIG_FB=y
CONFIG_FB_CFB_FILLRECT=y
CONFIG_FB_CFB_COPYAREA=y
CONFIG_FB_CFB_IMAGEBLIT=y
-CONFIG_FB_SOFT_CURSOR=y
# CONFIG_FB_MACMODES is not set
# CONFIG_FB_MODE_HELPERS is not set
# CONFIG_FB_TILEBLITTING is not set
@@ -671,6 +694,7 @@ CONFIG_FB_SOFT_CURSOR=y
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_IMSTT is not set
CONFIG_FB_STI=y
+# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_NVIDIA is not set
# CONFIG_FB_RIVA is not set
# CONFIG_FB_MATROX is not set
@@ -683,9 +707,7 @@ CONFIG_FB_STI=y
# CONFIG_FB_KYRO is not set
# CONFIG_FB_3DFX is not set
# CONFIG_FB_VOODOO1 is not set
-# CONFIG_FB_CYBLA is not set
# CONFIG_FB_TRIDENT is not set
-# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_VIRTUAL is not set
#
@@ -695,6 +717,7 @@ CONFIG_DUMMY_CONSOLE=y
CONFIG_DUMMY_CONSOLE_COLUMNS=160
CONFIG_DUMMY_CONSOLE_ROWS=64
CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
CONFIG_STI_CONSOLE=y
# CONFIG_FONTS is not set
CONFIG_FONT_8x8=y
@@ -713,7 +736,85 @@ CONFIG_LOGO_PARISC_CLUT224=y
#
# Sound
#
-# CONFIG_SOUND is not set
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_SEQUENCER=y
+# CONFIG_SND_SEQ_DUMMY is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_SEQUENCER_OSS=y
+CONFIG_SND_SUPPORT_OLD_API=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# PCI devices
+#
+# CONFIG_SND_AD1889 is not set
+# CONFIG_SND_ALI5451 is not set
+# CONFIG_SND_ATIIXP is not set
+# CONFIG_SND_ATIIXP_MODEM is not set
+# CONFIG_SND_AU8810 is not set
+# CONFIG_SND_AU8820 is not set
+# CONFIG_SND_AU8830 is not set
+# CONFIG_SND_BT87X is not set
+# CONFIG_SND_CA0106 is not set
+# CONFIG_SND_CMIPCI is not set
+# CONFIG_SND_CS4281 is not set
+# CONFIG_SND_CS46XX is not set
+# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_ENS1370 is not set
+# CONFIG_SND_ENS1371 is not set
+# CONFIG_SND_ES1938 is not set
+# CONFIG_SND_ES1968 is not set
+# CONFIG_SND_FM801 is not set
+# CONFIG_SND_HDA_INTEL is not set
+# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
+# CONFIG_SND_ICE1712 is not set
+# CONFIG_SND_ICE1724 is not set
+# CONFIG_SND_INTEL8X0 is not set
+# CONFIG_SND_KORG1212 is not set
+# CONFIG_SND_MAESTRO3 is not set
+# CONFIG_SND_MIXART is not set
+# CONFIG_SND_NM256 is not set
+# CONFIG_SND_PCXHR is not set
+# CONFIG_SND_RME32 is not set
+# CONFIG_SND_RME96 is not set
+# CONFIG_SND_RME9652 is not set
+# CONFIG_SND_SONICVIBES is not set
+# CONFIG_SND_TRIDENT is not set
+# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
+# CONFIG_SND_VX222 is not set
+# CONFIG_SND_YMFPCI is not set
+
+#
+# GSC devices
+#
+CONFIG_SND_HARMONY=y
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
#
# USB support
@@ -723,6 +824,10 @@ CONFIG_USB_ARCH_HAS_OHCI=y
# CONFIG_USB is not set
#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
# USB Gadget Support
#
# CONFIG_USB_GADGET is not set
@@ -877,18 +982,23 @@ CONFIG_NLS_DEFAULT="iso8859-1"
# Kernel hacking
#
# CONFIG_PRINTK_TIME is not set
-CONFIG_DEBUG_KERNEL=y
CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=16
CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_SCHEDSTATS is not set
# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_MUTEXES is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_KOBJECT is not set
# CONFIG_DEBUG_INFO is not set
# CONFIG_DEBUG_IOREMAP is not set
# CONFIG_DEBUG_FS is not set
+# CONFIG_DEBUG_VM is not set
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_DEBUG_RODATA is not set
#
# Security options
diff --git a/arch/parisc/hpux/entry_hpux.S b/arch/parisc/hpux/entry_hpux.S
index fa9bf38787e..31c8cccfba3 100644
--- a/arch/parisc/hpux/entry_hpux.S
+++ b/arch/parisc/hpux/entry_hpux.S
@@ -22,10 +22,9 @@
#include <linux/linkage.h>
#include <asm/unistd.h>
- .text
-
#define ENTRY_NAME(_name_) .word _name_
+ .section .rodata,"a"
.align 4
.export hpux_call_table
.import hpux_unimplemented_wrapper
diff --git a/arch/parisc/kernel/drivers.c b/arch/parisc/kernel/drivers.c
index 2d804e2d16d..3d569a485a1 100644
--- a/arch/parisc/kernel/drivers.c
+++ b/arch/parisc/kernel/drivers.c
@@ -408,11 +408,10 @@ static void setup_bus_id(struct parisc_device *padev)
struct parisc_device * create_tree_node(char id, struct device *parent)
{
- struct parisc_device *dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ struct parisc_device *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return NULL;
- memset(dev, 0, sizeof(*dev));
dev->hw_path = id;
dev->id.hw_type = HPHW_FAULTY;
diff --git a/arch/parisc/kernel/parisc_ksyms.c b/arch/parisc/kernel/parisc_ksyms.c
index f40a777dd38..1d00c365f2b 100644
--- a/arch/parisc/kernel/parisc_ksyms.c
+++ b/arch/parisc/kernel/parisc_ksyms.c
@@ -48,9 +48,6 @@ EXPORT_SYMBOL(strrchr);
EXPORT_SYMBOL(strstr);
EXPORT_SYMBOL(strpbrk);
-#include <linux/pm.h>
-EXPORT_SYMBOL(pm_power_off);
-
#include <asm/atomic.h>
EXPORT_SYMBOL(__xchg8);
EXPORT_SYMBOL(__xchg32);
diff --git a/arch/parisc/kernel/pci.c b/arch/parisc/kernel/pci.c
index 88cba49c530..79c7db2705f 100644
--- a/arch/parisc/kernel/pci.c
+++ b/arch/parisc/kernel/pci.c
@@ -47,18 +47,17 @@
* this makes the boot time much longer than necessary.
* 20ms seems to work for all the HP PCI implementations to date.
*
- * XXX: turn into a #defined constant in <asm/pci.h> ?
+ * #define pci_post_reset_delay 50
*/
-int pci_post_reset_delay = 50;
-struct pci_port_ops *pci_port;
-struct pci_bios_ops *pci_bios;
+struct pci_port_ops *pci_port __read_mostly;
+struct pci_bios_ops *pci_bios __read_mostly;
-int pci_hba_count = 0;
+static int pci_hba_count __read_mostly;
/* parisc_pci_hba used by pci_port->in/out() ops to lookup bus data. */
#define PCI_HBA_MAX 32
-struct pci_hba_data *parisc_pci_hba[PCI_HBA_MAX];
+static struct pci_hba_data *parisc_pci_hba[PCI_HBA_MAX] __read_mostly;
/********************************************************************
@@ -259,8 +258,10 @@ void __devinit pcibios_resource_to_bus(struct pci_dev *dev,
void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res,
struct pci_bus_region *region)
{
+#ifdef CONFIG_64BIT
struct pci_bus *bus = dev->bus;
struct pci_hba_data *hba = HBA_DATA(bus->bridge->platform_data);
+#endif
if (res->flags & IORESOURCE_MEM) {
res->start = PCI_HOST_ADDR(hba, region->start);
diff --git a/arch/parisc/kernel/perf.c b/arch/parisc/kernel/perf.c
index 11d406cd0b3..53f861c82f9 100644
--- a/arch/parisc/kernel/perf.c
+++ b/arch/parisc/kernel/perf.c
@@ -68,20 +68,20 @@ struct rdr_tbl_ent {
};
static int perf_processor_interface __read_mostly = UNKNOWN_INTF;
-static int perf_enabled __read_mostly = 0;
+static int perf_enabled __read_mostly;
static spinlock_t perf_lock;
-struct parisc_device *cpu_device __read_mostly = NULL;
+struct parisc_device *cpu_device __read_mostly;
/* RDRs to write for PCX-W */
-static int perf_rdrs_W[] =
+static const int perf_rdrs_W[] =
{ 0, 1, 4, 5, 6, 15, 16, 17, 18, 20, 21, 22, 23, 24, 25, -1 };
/* RDRs to write for PCX-U */
-static int perf_rdrs_U[] =
+static const int perf_rdrs_U[] =
{ 0, 1, 4, 5, 6, 7, 16, 17, 18, 20, 21, 22, 23, 24, 25, -1 };
/* RDR register descriptions for PCX-W */
-static struct rdr_tbl_ent perf_rdr_tbl_W[] = {
+static const struct rdr_tbl_ent perf_rdr_tbl_W[] = {
{ 19, 1, 8 }, /* RDR 0 */
{ 16, 1, 16 }, /* RDR 1 */
{ 72, 2, 0 }, /* RDR 2 */
@@ -117,7 +117,7 @@ static struct rdr_tbl_ent perf_rdr_tbl_W[] = {
};
/* RDR register descriptions for PCX-U */
-static struct rdr_tbl_ent perf_rdr_tbl_U[] = {
+static const struct rdr_tbl_ent perf_rdr_tbl_U[] = {
{ 19, 1, 8 }, /* RDR 0 */
{ 32, 1, 16 }, /* RDR 1 */
{ 20, 1, 0 }, /* RDR 2 */
@@ -156,7 +156,7 @@ static struct rdr_tbl_ent perf_rdr_tbl_U[] = {
* A non-zero write_control in the above tables is a byte offset into
* this array.
*/
-static uint64_t perf_bitmasks[] = {
+static const uint64_t perf_bitmasks[] = {
0x0000000000000000ul, /* first dbl word must be zero */
0xfdffe00000000000ul, /* RDR0 bitmask */
0x003f000000000000ul, /* RDR1 bitmask */
@@ -173,7 +173,7 @@ static uint64_t perf_bitmasks[] = {
* Write control bitmasks for Pa-8700 processor given
* somethings have changed slightly.
*/
-static uint64_t perf_bitmasks_piranha[] = {
+static const uint64_t perf_bitmasks_piranha[] = {
0x0000000000000000ul, /* first dbl word must be zero */
0xfdffe00000000000ul, /* RDR0 bitmask */
0x003f000000000000ul, /* RDR1 bitmask */
@@ -186,7 +186,7 @@ static uint64_t perf_bitmasks_piranha[] = {
0xfffc000000000000ul
};
-static uint64_t *bitmask_array; /* array of bitmasks to use */
+static const uint64_t *bitmask_array; /* array of bitmasks to use */
/******************************************************************************
* Function Prototypes
@@ -200,7 +200,7 @@ static ssize_t perf_write(struct file *file, const char __user *buf, size_t coun
static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
static void perf_start_counters(void);
static int perf_stop_counters(uint32_t *raddr);
-static struct rdr_tbl_ent * perf_rdr_get_entry(uint32_t rdr_num);
+static const struct rdr_tbl_ent * perf_rdr_get_entry(uint32_t rdr_num);
static int perf_rdr_read_ubuf(uint32_t rdr_num, uint64_t *buffer);
static int perf_rdr_clear(uint32_t rdr_num);
static int perf_write_image(uint64_t *memaddr);
@@ -444,7 +444,6 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
uint32_t raddr[4];
int error = 0;
- lock_kernel();
switch (cmd) {
case PA_PERF_ON:
@@ -477,8 +476,6 @@ static long perf_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
error = -ENOTTY;
}
- unlock_kernel();
-
return error;
}
@@ -655,7 +652,7 @@ static int perf_stop_counters(uint32_t *raddr)
* Retrieve a pointer to the description of what this
* RDR contains.
*/
-static struct rdr_tbl_ent * perf_rdr_get_entry(uint32_t rdr_num)
+static const struct rdr_tbl_ent * perf_rdr_get_entry(uint32_t rdr_num)
{
if (perf_processor_interface == ONYX_INTF) {
return &perf_rdr_tbl_U[rdr_num];
@@ -673,7 +670,7 @@ static int perf_rdr_read_ubuf(uint32_t rdr_num, uint64_t *buffer)
{
uint64_t data, data_mask = 0;
uint32_t width, xbits, i;
- struct rdr_tbl_ent *tentry;
+ const struct rdr_tbl_ent *tentry;
tentry = perf_rdr_get_entry(rdr_num);
if ((width = tentry->width) == 0)
@@ -721,7 +718,7 @@ static int perf_rdr_read_ubuf(uint32_t rdr_num, uint64_t *buffer)
*/
static int perf_rdr_clear(uint32_t rdr_num)
{
- struct rdr_tbl_ent *tentry;
+ const struct rdr_tbl_ent *tentry;
int32_t i;
tentry = perf_rdr_get_entry(rdr_num);
@@ -753,10 +750,11 @@ static int perf_write_image(uint64_t *memaddr)
uint64_t buffer[MAX_RDR_WORDS];
uint64_t *bptr;
uint32_t dwords;
- uint32_t *intrigue_rdr;
- uint64_t *intrigue_bitmask, tmp64;
+ const uint32_t *intrigue_rdr;
+ const uint64_t *intrigue_bitmask;
+ uint64_t tmp64;
void __iomem *runway;
- struct rdr_tbl_ent *tentry;
+ const struct rdr_tbl_ent *tentry;
int i;
/* Clear out counters */
@@ -830,7 +828,7 @@ static int perf_write_image(uint64_t *memaddr)
*/
static void perf_rdr_write(uint32_t rdr_num, uint64_t *buffer)
{
- struct rdr_tbl_ent *tentry;
+ const struct rdr_tbl_ent *tentry;
int32_t i;
printk("perf_rdr_write\n");
diff --git a/arch/parisc/kernel/perf_images.h b/arch/parisc/kernel/perf_images.h
index d9562fe3f75..7fef9644df4 100644
--- a/arch/parisc/kernel/perf_images.h
+++ b/arch/parisc/kernel/perf_images.h
@@ -25,7 +25,7 @@
#define PCXU_IMAGE_SIZE 584
-static uint32_t onyx_images[][PCXU_IMAGE_SIZE/sizeof(uint32_t)] = {
+static uint32_t onyx_images[][PCXU_IMAGE_SIZE/sizeof(uint32_t)] __read_mostly = {
/*
* CPI:
*
@@ -2093,7 +2093,7 @@ static uint32_t onyx_images[][PCXU_IMAGE_SIZE/sizeof(uint32_t)] = {
};
#define PCXW_IMAGE_SIZE 576
-static uint32_t cuda_images[][PCXW_IMAGE_SIZE/sizeof(uint32_t)] = {
+static uint32_t cuda_images[][PCXW_IMAGE_SIZE/sizeof(uint32_t)] __read_mostly = {
/*
* CPI: FROM CPI.IDF (Image 0)
*
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c
index 5da41677e70..e8dea417711 100644
--- a/arch/parisc/kernel/process.c
+++ b/arch/parisc/kernel/process.c
@@ -54,27 +54,6 @@
#include <asm/uaccess.h>
#include <asm/unwind.h>
-static int hlt_counter __read_mostly;
-
-/*
- * Power off function, if any
- */
-void (*pm_power_off)(void);
-
-void disable_hlt(void)
-{
- hlt_counter++;
-}
-
-EXPORT_SYMBOL(disable_hlt);
-
-void enable_hlt(void)
-{
- hlt_counter--;
-}
-
-EXPORT_SYMBOL(enable_hlt);
-
void default_idle(void)
{
barrier();
@@ -102,12 +81,7 @@ void cpu_idle(void)
}
-#ifdef __LP64__
-#define COMMAND_GLOBAL 0xfffffffffffe0030UL
-#else
-#define COMMAND_GLOBAL 0xfffe0030
-#endif
-
+#define COMMAND_GLOBAL F_EXTEND(0xfffe0030)
#define CMD_RESET 5 /* reset any module */
/*
@@ -162,6 +136,7 @@ void machine_halt(void)
*/
}
+void (*chassis_power_off)(void);
/*
* This routine is called from sys_reboot to actually turn off the
@@ -170,8 +145,8 @@ void machine_halt(void)
void machine_power_off(void)
{
/* If there is a registered power off handler, call it. */
- if(pm_power_off)
- pm_power_off();
+ if (chassis_power_off)
+ chassis_power_off();
/* Put the soft power button back under hardware control.
* If the user had already pressed the power button, the
@@ -187,6 +162,8 @@ void machine_power_off(void)
KERN_EMERG "Please power this system off now.");
}
+void (*pm_power_off)(void) = machine_power_off;
+EXPORT_SYMBOL(pm_power_off);
/*
* Create a kernel thread
diff --git a/arch/parisc/kernel/ptrace.c b/arch/parisc/kernel/ptrace.c
index 27160e8bf15..413292f1a4a 100644
--- a/arch/parisc/kernel/ptrace.c
+++ b/arch/parisc/kernel/ptrace.c
@@ -91,7 +91,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
int copied;
#ifdef __LP64__
- if (is_compat_task(child)) {
+ if (personality(child->personality) == PER_LINUX32) {
unsigned int tmp;
addr &= 0xffffffffL;
@@ -123,7 +123,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
case PTRACE_POKEDATA:
ret = 0;
#ifdef __LP64__
- if (is_compat_task(child)) {
+ if (personality(child->personality) == PER_LINUX32) {
unsigned int tmp = (unsigned int)data;
DBG("sys_ptrace(POKE%s, %d, %lx, %lx)\n",
request == PTRACE_POKETEXT ? "TEXT" : "DATA",
@@ -146,7 +146,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
case PTRACE_PEEKUSR: {
ret = -EIO;
#ifdef __LP64__
- if (is_compat_task(child)) {
+ if (personality(child->personality) == PER_LINUX32) {
unsigned int tmp;
if (addr & (sizeof(int)-1))
@@ -205,7 +205,7 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data)
goto out_tsk;
}
#ifdef __LP64__
- if (is_compat_task(child)) {
+ if (personality(child->personality) == PER_LINUX32) {
if (addr & (sizeof(int)-1))
goto out_tsk;
if ((addr = translate_usr_offset(addr)) < 0)
diff --git a/arch/parisc/kernel/signal.c b/arch/parisc/kernel/signal.c
index 3a25a7bd673..05767e83cf2 100644
--- a/arch/parisc/kernel/signal.c
+++ b/arch/parisc/kernel/signal.c
@@ -317,7 +317,7 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
if(personality(current->personality) == PER_LINUX32) {
DBG(1,"setup_rt_frame: frame->info = 0x%p\n", &compat_frame->info);
- err |= compat_copy_siginfo_to_user(&compat_frame->info, info);
+ err |= copy_siginfo_to_user32(&compat_frame->info, info);
DBG(1,"SETUP_RT_FRAME: 1\n");
compat_val = (compat_int_t)current->sas_ss_sp;
err |= __put_user(compat_val, &compat_frame->uc.uc_stack.ss_sp);
diff --git a/arch/parisc/kernel/signal32.c b/arch/parisc/kernel/signal32.c
index 0792e20efef..a6b4231cafa 100644
--- a/arch/parisc/kernel/signal32.c
+++ b/arch/parisc/kernel/signal32.c
@@ -31,7 +31,6 @@
#include <linux/types.h>
#include <linux/errno.h>
-#include <asm/compat_signal.h>
#include <asm/uaccess.h>
#include "signal32.h"
@@ -398,3 +397,104 @@ setup_sigcontext32(struct compat_sigcontext __user *sc, struct compat_regfile __
return err;
}
+
+int
+copy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from)
+{
+ unsigned long tmp;
+ int err;
+
+ if (!access_ok(VERIFY_READ, from, sizeof(compat_siginfo_t)))
+ return -EFAULT;
+
+ err = __get_user(to->si_signo, &from->si_signo);
+ err |= __get_user(to->si_errno, &from->si_errno);
+ err |= __get_user(to->si_code, &from->si_code);
+
+ if (to->si_code < 0)
+ err |= __copy_from_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
+ else {
+ switch (to->si_code >> 16) {
+ case __SI_CHLD >> 16:
+ err |= __get_user(to->si_utime, &from->si_utime);
+ err |= __get_user(to->si_stime, &from->si_stime);
+ err |= __get_user(to->si_status, &from->si_status);
+ default:
+ err |= __get_user(to->si_pid, &from->si_pid);
+ err |= __get_user(to->si_uid, &from->si_uid);
+ break;
+ case __SI_FAULT >> 16:
+ err |= __get_user(tmp, &from->si_addr);
+ to->si_addr = (void __user *) tmp;
+ break;
+ case __SI_POLL >> 16:
+ err |= __get_user(to->si_band, &from->si_band);
+ err |= __get_user(to->si_fd, &from->si_fd);
+ break;
+ case __SI_RT >> 16: /* This is not generated by the kernel as of now. */
+ case __SI_MESGQ >> 16:
+ err |= __get_user(to->si_pid, &from->si_pid);
+ err |= __get_user(to->si_uid, &from->si_uid);
+ err |= __get_user(to->si_int, &from->si_int);
+ break;
+ }
+ }
+ return err;
+}
+
+int
+copy_siginfo_to_user32 (compat_siginfo_t __user *to, siginfo_t *from)
+{
+ unsigned int addr;
+ int err;
+
+ if (!access_ok(VERIFY_WRITE, to, sizeof(compat_siginfo_t)))
+ return -EFAULT;
+
+ /* If you change siginfo_t structure, please be sure
+ this code is fixed accordingly.
+ It should never copy any pad contained in the structure
+ to avoid security leaks, but must copy the generic
+ 3 ints plus the relevant union member.
+ This routine must convert siginfo from 64bit to 32bit as well
+ at the same time. */
+ err = __put_user(from->si_signo, &to->si_signo);
+ err |= __put_user(from->si_errno, &to->si_errno);
+ err |= __put_user((short)from->si_code, &to->si_code);
+ if (from->si_code < 0)
+ err |= __copy_to_user(&to->_sifields._pad, &from->_sifields._pad, SI_PAD_SIZE);
+ else {
+ switch (from->si_code >> 16) {
+ case __SI_CHLD >> 16:
+ err |= __put_user(from->si_utime, &to->si_utime);
+ err |= __put_user(from->si_stime, &to->si_stime);
+ err |= __put_user(from->si_status, &to->si_status);
+ default:
+ err |= __put_user(from->si_pid, &to->si_pid);
+ err |= __put_user(from->si_uid, &to->si_uid);
+ break;
+ case __SI_FAULT >> 16:
+ /* avoid type-checking warnings by copying _pad[0] in lieu of si_addr... */
+ err |= __put_user(from->_sifields._pad[0], &to->si_addr);
+ break;
+ case __SI_POLL >> 16:
+ err |= __put_user(from->si_band, &to->si_band);
+ err |= __put_user(from->si_fd, &to->si_fd);
+ break;
+ case __SI_TIMER >> 16:
+ err |= __put_user(from->si_tid, &to->si_tid);
+ err |= __put_user(from->si_overrun, &to->si_overrun);
+ addr = (unsigned long) from->si_ptr;
+ err |= __put_user(addr, &to->si_ptr);
+ break;
+ case __SI_RT >> 16: /* Not generated by the kernel as of now. */
+ case __SI_MESGQ >> 16:
+ err |= __put_user(from->si_uid, &to->si_uid);
+ err |= __put_user(from->si_pid, &to->si_pid);
+ addr = (unsigned long) from->si_ptr;
+ err |= __put_user(addr, &to->si_ptr);
+ break;
+ }
+ }
+ return err;
+}
diff --git a/arch/parisc/kernel/signal32.h b/arch/parisc/kernel/signal32.h
index 4d1569e717c..e39b38a67a8 100644
--- a/arch/parisc/kernel/signal32.h
+++ b/arch/parisc/kernel/signal32.h
@@ -20,8 +20,34 @@
#define _PARISC64_KERNEL_SIGNAL32_H
#include <linux/compat.h>
-#include <asm/compat_signal.h>
-#include <asm/compat_rt_sigframe.h>
+
+typedef compat_uptr_t compat_sighandler_t;
+
+typedef struct compat_sigaltstack {
+ compat_uptr_t ss_sp;
+ compat_int_t ss_flags;
+ compat_size_t ss_size;
+} compat_stack_t;
+
+/* Most things should be clean enough to redefine this at will, if care
+ is taken to make libc match. */
+
+struct compat_sigaction {
+ compat_sighandler_t sa_handler;
+ compat_uint_t sa_flags;
+ compat_sigset_t sa_mask; /* mask last for extensibility */
+};
+
+/* 32-bit ucontext as seen from an 64-bit kernel */
+struct compat_ucontext {
+ compat_uint_t uc_flags;
+ compat_uptr_t uc_link;
+ compat_stack_t uc_stack; /* struct compat_sigaltstack (12 bytes)*/
+ /* FIXME: Pad out to get uc_mcontext to start at an 8-byte aligned boundary */
+ compat_uint_t pad[1];
+ struct compat_sigcontext uc_mcontext;
+ compat_sigset_t uc_sigmask; /* mask last for extensibility */
+};
/* ELF32 signal handling */
@@ -29,6 +55,103 @@ struct k_sigaction32 {
struct compat_sigaction sa;
};
+typedef struct compat_siginfo {
+ int si_signo;
+ int si_errno;
+ int si_code;
+
+ union {
+ int _pad[((128/sizeof(int)) - 3)];
+
+ /* kill() */
+ struct {
+ unsigned int _pid; /* sender's pid */
+ unsigned int _uid; /* sender's uid */
+ } _kill;
+
+ /* POSIX.1b timers */
+ struct {
+ compat_timer_t _tid; /* timer id */
+ int _overrun; /* overrun count */
+ char _pad[sizeof(unsigned int) - sizeof(int)];
+ compat_sigval_t _sigval; /* same as below */
+ int _sys_private; /* not to be passed to user */
+ } _timer;
+
+ /* POSIX.1b signals */
+ struct {
+ unsigned int _pid; /* sender's pid */
+ unsigned int _uid; /* sender's uid */
+ compat_sigval_t _sigval;
+ } _rt;
+
+ /* SIGCHLD */
+ struct {
+ unsigned int _pid; /* which child */
+ unsigned int _uid; /* sender's uid */
+ int _status; /* exit code */
+ compat_clock_t _utime;
+ compat_clock_t _stime;
+ } _sigchld;
+
+ /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+ struct {
+ unsigned int _addr; /* faulting insn/memory ref. */
+ } _sigfault;
+
+ /* SIGPOLL */
+ struct {
+ int _band; /* POLL_IN, POLL_OUT, POLL_MSG */
+ int _fd;
+ } _sigpoll;
+ } _sifields;
+} compat_siginfo_t;
+
+int copy_siginfo_to_user32 (compat_siginfo_t __user *to, siginfo_t *from);
+int copy_siginfo_from_user32 (siginfo_t *to, compat_siginfo_t __user *from);
+
+/* In a deft move of uber-hackery, we decide to carry the top half of all
+ * 64-bit registers in a non-portable, non-ABI, hidden structure.
+ * Userspace can read the hidden structure if it *wants* but is never
+ * guaranteed to be in the same place. Infact the uc_sigmask from the
+ * ucontext_t structure may push the hidden register file downards
+ */
+struct compat_regfile {
+ /* Upper half of all the 64-bit registers that were truncated
+ on a copy to a 32-bit userspace */
+ compat_int_t rf_gr[32];
+ compat_int_t rf_iasq[2];
+ compat_int_t rf_iaoq[2];
+ compat_int_t rf_sar;
+};
+
+#define COMPAT_SIGRETURN_TRAMP 4
+#define COMPAT_SIGRESTARTBLOCK_TRAMP 5
+#define COMPAT_TRAMP_SIZE (COMPAT_SIGRETURN_TRAMP + \
+ COMPAT_SIGRESTARTBLOCK_TRAMP)
+
+struct compat_rt_sigframe {
+ /* XXX: Must match trampoline size in arch/parisc/kernel/signal.c
+ Secondary to that it must protect the ERESTART_RESTARTBLOCK
+ trampoline we left on the stack (we were bad and didn't
+ change sp so we could run really fast.) */
+ compat_uint_t tramp[COMPAT_TRAMP_SIZE];
+ compat_siginfo_t info;
+ struct compat_ucontext uc;
+ /* Hidden location of truncated registers, *must* be last. */
+ struct compat_regfile regs;
+};
+
+/*
+ * The 32-bit ABI wants at least 48 bytes for a function call frame:
+ * 16 bytes for arg0-arg3, and 32 bytes for magic (the only part of
+ * which Linux/parisc uses is sp-20 for the saved return pointer...)
+ * Then, the stack pointer must be rounded to a cache line (64 bytes).
+ */
+#define SIGFRAME32 64
+#define FUNCTIONCALLFRAME32 48
+#define PARISC_RT_SIGFRAME_SIZE32 (((sizeof(struct compat_rt_sigframe) + FUNCTIONCALLFRAME32) + SIGFRAME32) & -SIGFRAME32)
+
void sigset_32to64(sigset_t *s64, compat_sigset_t *s32);
void sigset_64to32(compat_sigset_t *s32, sigset_t *s64);
int do_sigaltstack32 (const compat_stack_t __user *uss32,
diff --git a/arch/parisc/kernel/syscall.S b/arch/parisc/kernel/syscall.S
index d6616349289..af88afef41b 100644
--- a/arch/parisc/kernel/syscall.S
+++ b/arch/parisc/kernel/syscall.S
@@ -650,6 +650,8 @@ end_linux_gateway_page:
#define LWS_ENTRY(_name_) .word (lws_##_name_ - linux_gateway_page)
#endif
+ .section .rodata,"a"
+
.align 4096
/* Light-weight-syscall table */
/* Start of lws table. */
diff --git a/arch/parisc/kernel/syscall_table.S b/arch/parisc/kernel/syscall_table.S
index 32cbc048932..51d2480627d 100644
--- a/arch/parisc/kernel/syscall_table.S
+++ b/arch/parisc/kernel/syscall_table.S
@@ -374,5 +374,24 @@
ENTRY_SAME(keyctl)
ENTRY_SAME(ioprio_set)
ENTRY_SAME(ioprio_get)
+ ENTRY_SAME(inotify_init)
+ ENTRY_SAME(inotify_add_watch) /* 270 */
+ ENTRY_SAME(inotify_rm_watch)
+ ENTRY_COMP(pselect6)
+ ENTRY_COMP(ppoll)
+ ENTRY_SAME(migrate_pages)
+ ENTRY_COMP(openat) /* 275 */
+ ENTRY_SAME(mkdirat)
+ ENTRY_SAME(mknodat)
+ ENTRY_SAME(fchownat)
+ ENTRY_COMP(futimesat)
+ ENTRY_COMP(newfstatat) /* 280 */
+ ENTRY_SAME(unlinkat)
+ ENTRY_SAME(renameat)
+ ENTRY_SAME(linkat)
+ ENTRY_SAME(symlinkat)
+ ENTRY_SAME(readlinkat) /* 285 */
+ ENTRY_SAME(fchmodat)
+ ENTRY_SAME(faccessat)
/* Nothing yet */
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c
index 15914f0235a..ff200608c85 100644
--- a/arch/parisc/kernel/traps.c
+++ b/arch/parisc/kernel/traps.c
@@ -193,10 +193,9 @@ void show_stack(struct task_struct *task, unsigned long *s)
HERE:
asm volatile ("copy %%r30, %0" : "=r"(sp));
- r = (struct pt_regs *)kmalloc(sizeof(struct pt_regs), GFP_KERNEL);
+ r = kzalloc(sizeof(struct pt_regs), GFP_KERNEL);
if (!r)
return;
- memset(r, 0, sizeof(struct pt_regs));
r->iaoq[0] = (unsigned long)&&HERE;
r->gr[2] = (unsigned long)__builtin_return_address(0);
r->gr[30] = sp;
diff --git a/arch/parisc/math-emu/decode_exc.c b/arch/parisc/math-emu/decode_exc.c
index f84f2586672..66c8a9f6a27 100644
--- a/arch/parisc/math-emu/decode_exc.c
+++ b/arch/parisc/math-emu/decode_exc.c
@@ -337,6 +337,7 @@ decode_fpu(unsigned int Fpu_register[], unsigned int trap_counts[])
}
break;
case INVALIDEXCEPTION:
+ case OPC_2E_INVALIDEXCEPTION:
update_trap_counts(Fpu_register, aflags, bflags, trap_counts);
return SIGNALCODE(SIGFPE, FPE_FLTINV);
case DIVISIONBYZEROEXCEPTION:
diff --git a/arch/parisc/mm/init.c b/arch/parisc/mm/init.c
index 720287d46e5..7847ca13d6c 100644
--- a/arch/parisc/mm/init.c
+++ b/arch/parisc/mm/init.c
@@ -371,17 +371,11 @@ static void __init setup_bootmem(void)
void free_initmem(void)
{
- /* FIXME: */
-#if 0
- printk(KERN_INFO "NOT FREEING INITMEM (%dk)\n",
- (&__init_end - &__init_begin) >> 10);
- return;
-#else
unsigned long addr;
printk(KERN_INFO "Freeing unused kernel memory: ");
-#if 1
+#ifdef CONFIG_DEBUG_KERNEL
/* Attempt to catch anyone trying to execute code here
* by filling the page with BRK insns.
*
@@ -414,9 +408,21 @@ void free_initmem(void)
pdc_chassis_send_status(PDC_CHASSIS_DIRECT_BCOMPLETE);
printk("%luk freed\n", (unsigned long)(&__init_end - &__init_begin) >> 10);
-#endif
}
+
+#ifdef CONFIG_DEBUG_RODATA
+void mark_rodata_ro(void)
+{
+ extern char __start_rodata, __end_rodata;
+ /* rodata memory was already mapped with KERNEL_RO access rights by
+ pagetable_init() and map_pages(). No need to do additional stuff here */
+ printk (KERN_INFO "Write protecting the kernel read-only data: %luk\n",
+ (unsigned long)(&__end_rodata - &__start_rodata) >> 10);
+}
+#endif
+
+
/*
* Just an arbitrary offset to serve as a "hole" between mapping areas
* (between top of physical memory and a potential pcxl dma mapping
@@ -477,11 +483,6 @@ void __init mem_init(void)
}
-int do_check_pgt_cache(int low, int high)
-{
- return 0;
-}
-
unsigned long *empty_zero_page __read_mostly;
void show_mem(void)
@@ -690,7 +691,7 @@ static void __init pagetable_init(void)
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_end && initrd_end > mem_limit) {
- printk("initrd: mapping %08lx-%08lx\n", initrd_start, initrd_end);
+ printk(KERN_INFO "initrd: mapping %08lx-%08lx\n", initrd_start, initrd_end);
map_pages(initrd_start, __pa(initrd_start),
initrd_end - initrd_start, PAGE_KERNEL);
}
@@ -792,8 +793,6 @@ map_hpux_gateway_page(struct task_struct *tsk, struct mm_struct *mm)
EXPORT_SYMBOL(map_hpux_gateway_page);
#endif
-extern void flush_tlb_all_local(void);
-
void __init paging_init(void)
{
int i;
@@ -802,7 +801,7 @@ void __init paging_init(void)
pagetable_init();
gateway_init();
flush_cache_all_local(); /* start with known state */
- flush_tlb_all_local();
+ flush_tlb_all_local(NULL);
for (i = 0; i < npmem_ranges; i++) {
unsigned long zones_size[MAX_NR_ZONES] = { 0, 0, 0 };
@@ -993,7 +992,7 @@ void flush_tlb_all(void)
do_recycle++;
}
spin_unlock(&sid_lock);
- on_each_cpu((void (*)(void *))flush_tlb_all_local, NULL, 1, 1);
+ on_each_cpu(flush_tlb_all_local, NULL, 1, 1);
if (do_recycle) {
spin_lock(&sid_lock);
recycle_sids(recycle_ndirty,recycle_dirty_array);
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
index 6e27ac68ec3..83b33fe1923 100644
--- a/arch/s390/kernel/compat_wrapper.S
+++ b/arch/s390/kernel/compat_wrapper.S
@@ -1486,7 +1486,7 @@ sys_inotify_rm_watch_wrapper:
.globl compat_sys_openat_wrapper
compat_sys_openat_wrapper:
- lgfr %r2,%r2 # int
+ llgfr %r2,%r2 # unsigned int
llgtr %r3,%r3 # const char *
lgfr %r4,%r4 # int
lgfr %r5,%r5 # int
@@ -1518,14 +1518,14 @@ sys_fchownat_wrapper:
.globl compat_sys_futimesat_wrapper
compat_sys_futimesat_wrapper:
- lgfr %r2,%r2 # int
+ llgfr %r2,%r2 # unsigned int
llgtr %r3,%r3 # char *
llgtr %r4,%r4 # struct timeval *
jg compat_sys_futimesat
.globl compat_sys_newfstatat_wrapper
compat_sys_newfstatat_wrapper:
- lgfr %r2,%r2 # int
+ llgfr %r2,%r2 # unsigned int
llgtr %r3,%r3 # char *
llgtr %r4,%r4 # struct stat *
lgfr %r5,%r5 # int
diff --git a/arch/sparc64/boot/.gitignore b/arch/sparc64/boot/.gitignore
new file mode 100644
index 00000000000..36356f9d498
--- /dev/null
+++ b/arch/sparc64/boot/.gitignore
@@ -0,0 +1,4 @@
+image
+tftpboot.img
+vmlinux.aout
+piggyback
diff --git a/arch/sparc64/defconfig b/arch/sparc64/defconfig
index 9ceddad0fb4..bc56a7d8830 100644
--- a/arch/sparc64/defconfig
+++ b/arch/sparc64/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.16-rc1
-# Wed Jan 18 13:41:02 2006
+# Linux kernel version: 2.6.16-rc2
+# Sat Feb 4 02:31:38 2006
#
CONFIG_SPARC=y
CONFIG_SPARC64=y
@@ -23,7 +23,6 @@ CONFIG_HZ=250
# Code maturity level options
#
CONFIG_EXPERIMENTAL=y
-CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_INIT_ENV_ARG_LIMIT=32
@@ -155,6 +154,7 @@ CONFIG_NET=y
#
# Networking options
#
+# CONFIG_NETDEBUG is not set
CONFIG_PACKET=y
CONFIG_PACKET_MMAP=y
CONFIG_UNIX=y
@@ -224,6 +224,11 @@ CONFIG_IP_DCCP_TFRC_LIB=m
# SCTP Configuration (EXPERIMENTAL)
#
# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
CONFIG_VLAN_8021Q=m
@@ -233,11 +238,6 @@ CONFIG_VLAN_8021Q=m
# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
-# CONFIG_TIPC is not set
# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
@@ -657,6 +657,7 @@ CONFIG_SERIAL_SUNSU_CONSOLE=y
CONFIG_SERIAL_SUNSAB=m
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
# CONFIG_LEGACY_PTYS is not set
@@ -1118,6 +1119,10 @@ CONFIG_USB_HIDDEV=y
#
#
+# EDAC - error detection and reporting (RAS)
+#
+
+#
# Misc Linux/SPARC drivers
#
CONFIG_SUN_OPENPROMIO=m
diff --git a/arch/v850/kernel/simcons.c b/arch/v850/kernel/simcons.c
index 7f0efaa025c..3975aa02cef 100644
--- a/arch/v850/kernel/simcons.c
+++ b/arch/v850/kernel/simcons.c
@@ -117,6 +117,7 @@ late_initcall(simcons_tty_init);
tty driver. */
void simcons_poll_tty (struct tty_struct *tty)
{
+ char buf[32]; /* Not the nicest way to do it but I need it correct first */
int flip = 0, send_break = 0;
struct pollfd pfd;
pfd.fd = 0;
@@ -124,21 +125,15 @@ void simcons_poll_tty (struct tty_struct *tty)
if (V850_SIM_SYSCALL (poll, &pfd, 1, 0) > 0) {
if (pfd.revents & POLLIN) {
- int left = TTY_FLIPBUF_SIZE - tty->flip.count;
-
- if (left > 0) {
- unsigned char *buf = tty->flip.char_buf_ptr;
- int rd = V850_SIM_SYSCALL (read, 0, buf, left);
-
- if (rd > 0) {
- tty->flip.count += rd;
- tty->flip.char_buf_ptr += rd;
- memset (tty->flip.flag_buf_ptr, 0, rd);
- tty->flip.flag_buf_ptr += rd;
- flip = 1;
- } else
- send_break = 1;
- }
+ /* Real block hardware knows the transfer size before
+ transfer so the new tty buffering doesn't try to handle
+ this rather weird simulator specific case well */
+ int rd = V850_SIM_SYSCALL (read, 0, buf, 32);
+ if (rd > 0) {
+ tty_insert_flip_string(tty, buf, rd);
+ flip = 1;
+ } else
+ send_break = 1;
} else if (pfd.revents & POLLERR)
send_break = 1;
}
diff --git a/arch/x86_64/Kconfig.debug b/arch/x86_64/Kconfig.debug
index fcb06a50fdd..ea31b4c6210 100644
--- a/arch/x86_64/Kconfig.debug
+++ b/arch/x86_64/Kconfig.debug
@@ -2,13 +2,6 @@ menu "Kernel hacking"
source "lib/Kconfig.debug"
-config INIT_DEBUG
- bool "Debug __init statements"
- depends on DEBUG_KERNEL
- help
- Fill __init and __initdata at the end of boot. This helps debugging
- illegal uses of __init and __initdata after initialization.
-
config DEBUG_RODATA
bool "Write protect kernel read-only data structures"
depends on DEBUG_KERNEL
diff --git a/arch/x86_64/defconfig b/arch/x86_64/defconfig
index 09a3eb74331..56832929a54 100644
--- a/arch/x86_64/defconfig
+++ b/arch/x86_64/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.15-git12
-# Mon Jan 16 13:09:08 2006
+# Linux kernel version: 2.6.16-rc1-git2
+# Thu Jan 19 10:05:21 2006
#
CONFIG_X86_64=y
CONFIG_64BIT=y
@@ -310,6 +310,11 @@ CONFIG_IPV6=y
# SCTP Configuration (EXPERIMENTAL)
#
# CONFIG_IP_SCTP is not set
+
+#
+# TIPC Configuration (EXPERIMENTAL)
+#
+# CONFIG_TIPC is not set
# CONFIG_ATM is not set
# CONFIG_BRIDGE is not set
# CONFIG_VLAN_8021Q is not set
@@ -319,11 +324,6 @@ CONFIG_IPV6=y
# CONFIG_ATALK is not set
# CONFIG_X25 is not set
# CONFIG_LAPB is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
-# CONFIG_TIPC is not set
# CONFIG_NET_DIVERT is not set
# CONFIG_ECONET is not set
# CONFIG_WAN_ROUTER is not set
@@ -1098,6 +1098,12 @@ CONFIG_USB_MON=y
#
#
+# EDAC - error detection and reporting (RAS)
+#
+# CONFIG_EDAC is not set
+# CONFIG_EDAC_POLL is not set
+
+#
# Firmware Drivers
#
# CONFIG_EDD is not set
@@ -1290,6 +1296,7 @@ CONFIG_DEBUG_FS=y
# CONFIG_DEBUG_VM is not set
# CONFIG_FRAME_POINTER is not set
# CONFIG_FORCED_INLINING is not set
+# CONFIG_UNWIND_INFO is not set
# CONFIG_RCU_TORTURE_TEST is not set
CONFIG_INIT_DEBUG=y
# CONFIG_DEBUG_RODATA is not set
diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c
index 5d3c5b07b8d..6147770b434 100644
--- a/arch/x86_64/kernel/apic.c
+++ b/arch/x86_64/kernel/apic.c
@@ -35,8 +35,12 @@
#include <asm/mach_apic.h>
#include <asm/nmi.h>
#include <asm/idle.h>
+#include <asm/proto.h>
+#include <asm/timex.h>
int apic_verbosity;
+int apic_runs_main_timer;
+int apic_calibrate_pmtmr __initdata;
int disable_apic_timer __initdata;
@@ -68,6 +72,26 @@ int get_maxlvt(void)
return maxlvt;
}
+/*
+ * 'what should we do if we get a hw irq event on an illegal vector'.
+ * each architecture has to answer this themselves.
+ */
+void ack_bad_irq(unsigned int irq)
+{
+ printk("unexpected IRQ trap at vector %02x\n", irq);
+ /*
+ * Currently unexpected vectors happen only on SMP and APIC.
+ * We _must_ ack these because every local APIC has only N
+ * irq slots per priority level, and a 'hanging, unacked' IRQ
+ * holds up an irq slot - in excessive cases (when multiple
+ * unexpected vectors occur) that might lock up the APIC
+ * completely.
+ * But don't ack when the APIC is disabled. -AK
+ */
+ if (!disable_apic)
+ ack_APIC_irq();
+}
+
void clear_local_APIC(void)
{
int maxlvt;
@@ -702,9 +726,17 @@ static void setup_APIC_timer(unsigned int clocks)
c2 |= inb_p(0x40) << 8;
} while (c2 - c1 < 300);
}
-
__setup_APIC_LVTT(clocks);
-
+ /* Turn off PIT interrupt if we use APIC timer as main timer.
+ Only works with the PM timer right now
+ TBD fix it for HPET too. */
+ if (vxtime.mode == VXTIME_PMTMR &&
+ smp_processor_id() == boot_cpu_id &&
+ apic_runs_main_timer == 1 &&
+ !cpu_isset(boot_cpu_id, timer_interrupt_broadcast_ipi_mask)) {
+ stop_timer_interrupt();
+ apic_runs_main_timer++;
+ }
local_irq_restore(flags);
}
@@ -735,14 +767,27 @@ static int __init calibrate_APIC_clock(void)
__setup_APIC_LVTT(1000000000);
apic_start = apic_read(APIC_TMCCT);
- rdtscl(tsc_start);
-
- do {
+#ifdef CONFIG_X86_PM_TIMER
+ if (apic_calibrate_pmtmr && pmtmr_ioport) {
+ pmtimer_wait(5000); /* 5ms wait */
apic = apic_read(APIC_TMCCT);
- rdtscl(tsc);
- } while ((tsc - tsc_start) < TICK_COUNT && (apic - apic_start) < TICK_COUNT);
+ result = (apic_start - apic) * 1000L / 5;
+ } else
+#endif
+ {
+ rdtscl(tsc_start);
+
+ do {
+ apic = apic_read(APIC_TMCCT);
+ rdtscl(tsc);
+ } while ((tsc - tsc_start) < TICK_COUNT &&
+ (apic - apic_start) < TICK_COUNT);
+
+ result = (apic_start - apic) * 1000L * cpu_khz /
+ (tsc - tsc_start);
+ }
+ printk("result %d\n", result);
- result = (apic_start - apic) * 1000L * cpu_khz / (tsc - tsc_start);
printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n",
result / 1000 / 1000, result / 1000 % 1000);
@@ -872,6 +917,8 @@ void smp_local_timer_interrupt(struct pt_regs *regs)
#ifdef CONFIG_SMP
update_process_times(user_mode(regs));
#endif
+ if (apic_runs_main_timer > 1 && smp_processor_id() == boot_cpu_id)
+ main_timer_handler(regs);
/*
* We take the 'long' return path, and there every subsystem
* grabs the appropriate locks (kernel lock/ irq lock).
@@ -924,7 +971,7 @@ void smp_apic_timer_interrupt(struct pt_regs *regs)
* multi-chassis. Use available data to take a good guess.
* If in doubt, go HPET.
*/
-__init int oem_force_hpet_timer(void)
+__cpuinit int oem_force_hpet_timer(void)
{
int i, clusters, zeros;
unsigned id;
@@ -1081,10 +1128,34 @@ static __init int setup_nolapic(char *str)
static __init int setup_noapictimer(char *str)
{
+ if (str[0] != ' ' && str[0] != 0)
+ return -1;
disable_apic_timer = 1;
return 0;
}
+static __init int setup_apicmaintimer(char *str)
+{
+ apic_runs_main_timer = 1;
+ nohpet = 1;
+ return 0;
+}
+__setup("apicmaintimer", setup_apicmaintimer);
+
+static __init int setup_noapicmaintimer(char *str)
+{
+ apic_runs_main_timer = -1;
+ return 0;
+}
+__setup("noapicmaintimer", setup_noapicmaintimer);
+
+static __init int setup_apicpmtimer(char *s)
+{
+ apic_calibrate_pmtmr = 1;
+ return setup_apicmaintimer(NULL);
+}
+__setup("apicpmtimer", setup_apicpmtimer);
+
/* dummy parsing: see setup.c */
__setup("disableapic", setup_disableapic);
diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S
index dbdba56e8fa..b150c87a08c 100644
--- a/arch/x86_64/kernel/entry.S
+++ b/arch/x86_64/kernel/entry.S
@@ -499,7 +499,9 @@ ENTRY(stub_rt_sigreturn)
movq %gs:pda_irqstackptr,%rax
cmoveq %rax,%rsp /*todo This needs CFI annotation! */
pushq %rdi # save old stack
+#ifndef CONFIG_DEBUG_INFO
CFI_ADJUST_CFA_OFFSET 8
+#endif
call \func
.endm
@@ -509,7 +511,9 @@ ENTRY(common_interrupt)
/* 0(%rsp): oldrsp-ARGOFFSET */
ret_from_intr:
popq %rdi
+#ifndef CONFIG_DEBUG_INFO
CFI_ADJUST_CFA_OFFSET -8
+#endif
cli
decl %gs:pda_irqcount
#ifdef CONFIG_DEBUG_INFO
@@ -922,7 +926,7 @@ KPROBE_ENTRY(debug)
.previous .text
/* runs on exception stack */
-ENTRY(nmi)
+KPROBE_ENTRY(nmi)
INTR_FRAME
pushq $-1
CFI_ADJUST_CFA_OFFSET 8
@@ -969,6 +973,7 @@ paranoid_schedule:
cli
jmp paranoid_userspace
CFI_ENDPROC
+ .previous .text
KPROBE_ENTRY(int3)
INTR_FRAME
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
index 1a5060b434b..4282d72b2a2 100644
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -304,6 +304,14 @@ void __init check_ioapic(void)
#endif
/* RED-PEN skip them on mptables too? */
return;
+ case PCI_VENDOR_ID_ATI:
+ if (apic_runs_main_timer != 0)
+ break;
+ printk(KERN_INFO
+ "ATI board detected. Using APIC/PM timer.\n");
+ apic_runs_main_timer = 1;
+ nohpet = 1;
+ return;
}
/* No multi-function device? */
diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c
index 13a2eada6c9..b8b9529fa89 100644
--- a/arch/x86_64/kernel/mce.c
+++ b/arch/x86_64/kernel/mce.c
@@ -380,7 +380,7 @@ static void __cpuinit mce_cpu_features(struct cpuinfo_x86 *c)
*/
void __cpuinit mcheck_init(struct cpuinfo_x86 *c)
{
- static cpumask_t mce_cpus __initdata = CPU_MASK_NONE;
+ static cpumask_t mce_cpus = CPU_MASK_NONE;
mce_cpu_quirks(c);
diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c
index 5fae6f0cd99..8be407a1f62 100644
--- a/arch/x86_64/kernel/nmi.c
+++ b/arch/x86_64/kernel/nmi.c
@@ -24,6 +24,7 @@
#include <linux/sysdev.h>
#include <linux/nmi.h>
#include <linux/sysctl.h>
+#include <linux/kprobes.h>
#include <asm/smp.h>
#include <asm/mtrr.h>
@@ -468,7 +469,7 @@ void touch_nmi_watchdog (void)
touch_softlockup_watchdog();
}
-void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason)
+void __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
{
int sum;
int touched = 0;
@@ -512,14 +513,14 @@ void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason)
}
}
-static int dummy_nmi_callback(struct pt_regs * regs, int cpu)
+static __kprobes int dummy_nmi_callback(struct pt_regs * regs, int cpu)
{
return 0;
}
static nmi_callback_t nmi_callback = dummy_nmi_callback;
-asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
+asmlinkage __kprobes void do_nmi(struct pt_regs * regs, long error_code)
{
int cpu = safe_smp_processor_id();
diff --git a/arch/x86_64/kernel/pci-dma.c b/arch/x86_64/kernel/pci-dma.c
index 2f5d8328e2b..4ed391edd47 100644
--- a/arch/x86_64/kernel/pci-dma.c
+++ b/arch/x86_64/kernel/pci-dma.c
@@ -107,6 +107,9 @@ dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
goto again;
}
+ /* Let low level make its own zone decisions */
+ gfp &= ~(GFP_DMA32|GFP_DMA);
+
if (dma_ops->alloc_coherent)
return dma_ops->alloc_coherent(dev, size,
dma_handle, gfp);
diff --git a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart.c
index c37fc7726ba..2fe23a6c361 100644
--- a/arch/x86_64/kernel/pci-gart.c
+++ b/arch/x86_64/kernel/pci-gart.c
@@ -457,9 +457,12 @@ int gart_map_sg(struct device *dev, struct scatterlist *sg, int nents, int dir)
error:
flush_gart(NULL);
gart_unmap_sg(dev, sg, nents, dir);
- /* When it was forced try again unforced */
- if (force_iommu)
- return dma_map_sg_nonforce(dev, sg, nents, dir);
+ /* When it was forced or merged try again in a dumb way */
+ if (force_iommu || iommu_merge) {
+ out = dma_map_sg_nonforce(dev, sg, nents, dir);
+ if (out > 0)
+ return out;
+ }
if (panic_on_overflow)
panic("dma_map_sg: overflow on %lu pages\n", pages);
iommu_full(dev, pages << PAGE_SHIFT, dir);
@@ -642,9 +645,18 @@ static int __init pci_iommu_init(void)
(no_agp && init_k8_gatt(&info) < 0)) {
no_iommu = 1;
no_iommu_init();
+ printk(KERN_INFO "PCI-DMA: Disabling IOMMU.\n");
+ if (end_pfn > MAX_DMA32_PFN) {
+ printk(KERN_ERR "WARNING more than 4GB of memory "
+ "but IOMMU not compiled in.\n"
+ KERN_ERR "WARNING 32bit PCI may malfunction.\n"
+ KERN_ERR "You might want to enable "
+ "CONFIG_GART_IOMMU\n");
+ }
return -1;
}
+ printk(KERN_INFO "PCI-DMA: using GART IOMMU.\n");
aper_size = info.aper_size * 1024 * 1024;
iommu_size = check_iommu_size(info.aper_base, aper_size);
iommu_pages = iommu_size >> PAGE_SHIFT;
@@ -718,7 +730,6 @@ static int __init pci_iommu_init(void)
flush_gart(NULL);
- printk(KERN_INFO "PCI-DMA: using GART IOMMU.\n");
dma_ops = &gart_dma_ops;
return 0;
diff --git a/arch/x86_64/kernel/pci-nommu.c b/arch/x86_64/kernel/pci-nommu.c
index e4156497519..44adcc2d5e5 100644
--- a/arch/x86_64/kernel/pci-nommu.c
+++ b/arch/x86_64/kernel/pci-nommu.c
@@ -88,12 +88,5 @@ void __init no_iommu_init(void)
{
if (dma_ops)
return;
- printk(KERN_INFO "PCI-DMA: Disabling IOMMU.\n");
dma_ops = &nommu_dma_ops;
- if (end_pfn > MAX_DMA32_PFN) {
- printk(KERN_ERR
- "WARNING more than 4GB of memory but IOMMU not compiled in.\n"
- KERN_ERR "WARNING 32bit PCI may malfunction.\n"
- KERN_ERR "You might want to enable CONFIG_GART_IOMMU\n");
- }
}
diff --git a/arch/x86_64/kernel/pci-swiotlb.c b/arch/x86_64/kernel/pci-swiotlb.c
index 3569a25ad7f..990ed67896f 100644
--- a/arch/x86_64/kernel/pci-swiotlb.c
+++ b/arch/x86_64/kernel/pci-swiotlb.c
@@ -35,8 +35,8 @@ void pci_swiotlb_init(void)
(end_pfn > MAX_DMA32_PFN || force_iommu))
swiotlb = 1;
if (swiotlb) {
- swiotlb_init();
printk(KERN_INFO "PCI-DMA: Using software bounce buffering for IO (SWIOTLB)\n");
+ swiotlb_init();
dma_ops = &swiotlb_dma_ops;
}
}
diff --git a/arch/x86_64/kernel/pmtimer.c b/arch/x86_64/kernel/pmtimer.c
index feb5f108dd2..5c51d10408a 100644
--- a/arch/x86_64/kernel/pmtimer.c
+++ b/arch/x86_64/kernel/pmtimer.c
@@ -80,6 +80,31 @@ int pmtimer_mark_offset(void)
return lost - 1;
}
+static unsigned pmtimer_wait_tick(void)
+{
+ u32 a, b;
+ for (a = b = inl(pmtmr_ioport) & ACPI_PM_MASK;
+ a == b;
+ b = inl(pmtmr_ioport) & ACPI_PM_MASK)
+ ;
+ return b;
+}
+
+/* note: wait time is rounded up to one tick */
+void pmtimer_wait(unsigned us)
+{
+ u32 a, b;
+ a = pmtimer_wait_tick();
+ do {
+ b = inl(pmtmr_ioport);
+ } while (cyc2us(b - a) < us);
+}
+
+void pmtimer_resume(void)
+{
+ last_pmtmr_tick = inl(pmtmr_ioport);
+}
+
unsigned int do_gettimeoffset_pm(void)
{
u32 now, offset, delta = 0;
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
index 8ded407e4a9..22a05dec81a 100644
--- a/arch/x86_64/kernel/process.c
+++ b/arch/x86_64/kernel/process.c
@@ -516,8 +516,10 @@ out:
* This could still be optimized:
* - fold all the options into a flag word and test it with a single test.
* - could test fs/gs bitsliced
+ *
+ * Kprobes not supported here. Set the probe on schedule instead.
*/
-struct task_struct *
+__kprobes struct task_struct *
__switch_to(struct task_struct *prev_p, struct task_struct *next_p)
{
struct thread_struct *prev = &prev_p->thread,
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index 28895c03cb1..363db5a003d 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -741,7 +741,7 @@ void __init setup_arch(char **cmdline_p)
e820_setup_gap();
#ifdef CONFIG_GART_IOMMU
- iommu_hole_init();
+ iommu_hole_init();
#endif
#ifdef CONFIG_VT
@@ -877,6 +877,7 @@ static void __init amd_detect_cmp(struct cpuinfo_x86 *c)
static int __init init_amd(struct cpuinfo_x86 *c)
{
int r;
+ unsigned level;
#ifdef CONFIG_SMP
unsigned long value;
@@ -899,6 +900,11 @@ static int __init init_amd(struct cpuinfo_x86 *c)
3DNow is IDd by bit 31 in extended CPUID (1*32+31) anyway */
clear_bit(0*32+31, &c->x86_capability);
+ /* On C+ stepping K8 rep microcode works well for copy/memset */
+ level = cpuid_eax(1);
+ if (c->x86 == 15 && ((level >= 0x0f48 && level < 0x0f50) || level >= 0x0f58))
+ set_bit(X86_FEATURE_REP_GOOD, &c->x86_capability);
+
r = get_model_name(c);
if (!r) {
switch (c->x86) {
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c
index f8c47c68844..c0844bffbf8 100644
--- a/arch/x86_64/kernel/time.c
+++ b/arch/x86_64/kernel/time.c
@@ -51,7 +51,7 @@ extern int using_apic_timer;
DEFINE_SPINLOCK(rtc_lock);
DEFINE_SPINLOCK(i8253_lock);
-static int nohpet __initdata = 0;
+int nohpet __initdata = 0;
static int notsc __initdata = 0;
#undef HPET_HACK_ENABLE_DANGEROUS
@@ -345,7 +345,7 @@ static noinline void handle_lost_ticks(int lost, struct pt_regs *regs)
#endif
}
-static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+void main_timer_handler(struct pt_regs *regs)
{
static unsigned long rtc_update = 0;
unsigned long tsc;
@@ -458,12 +458,17 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
write_sequnlock(&xtime_lock);
+}
+static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+ if (apic_runs_main_timer > 1)
+ return IRQ_HANDLED;
+ main_timer_handler(regs);
#ifdef CONFIG_X86_LOCAL_APIC
if (using_apic_timer)
smp_send_timer_broadcast_ipi();
#endif
-
return IRQ_HANDLED;
}
@@ -843,17 +848,43 @@ static int hpet_reenable(void)
return hpet_timer_stop_set_go(hpet_tick);
}
-void __init pit_init(void)
+#define PIT_MODE 0x43
+#define PIT_CH0 0x40
+
+static void __init __pit_init(int val, u8 mode)
{
unsigned long flags;
spin_lock_irqsave(&i8253_lock, flags);
- outb_p(0x34, 0x43); /* binary, mode 2, LSB/MSB, ch 0 */
- outb_p(LATCH & 0xff, 0x40); /* LSB */
- outb_p(LATCH >> 8, 0x40); /* MSB */
+ outb_p(mode, PIT_MODE);
+ outb_p(val & 0xff, PIT_CH0); /* LSB */
+ outb_p(val >> 8, PIT_CH0); /* MSB */
spin_unlock_irqrestore(&i8253_lock, flags);
}
+void __init pit_init(void)
+{
+ __pit_init(LATCH, 0x34); /* binary, mode 2, LSB/MSB, ch 0 */
+}
+
+void __init pit_stop_interrupt(void)
+{
+ __pit_init(0, 0x30); /* mode 0 */
+}
+
+void __init stop_timer_interrupt(void)
+{
+ char *name;
+ if (vxtime.hpet_address) {
+ name = "HPET";
+ hpet_timer_stop_set_go(0);
+ } else {
+ name = "PIT";
+ pit_stop_interrupt();
+ }
+ printk(KERN_INFO "timer: %s interrupt stopped.\n", name);
+}
+
int __init time_setup(char *str)
{
report_lost_ticks = 1;
@@ -932,7 +963,7 @@ void __init time_init(void)
* Make an educated guess if the TSC is trustworthy and synchronized
* over all CPUs.
*/
-__init int unsynchronized_tsc(void)
+__cpuinit int unsynchronized_tsc(void)
{
#ifdef CONFIG_SMP
if (oem_force_hpet_timer())
@@ -1016,9 +1047,21 @@ static int timer_resume(struct sys_device *dev)
write_seqlock_irqsave(&xtime_lock,flags);
xtime.tv_sec = sec;
xtime.tv_nsec = 0;
+ if (vxtime.mode == VXTIME_HPET) {
+ if (hpet_use_timer)
+ vxtime.last = hpet_readl(HPET_T0_CMP) - hpet_tick;
+ else
+ vxtime.last = hpet_readl(HPET_COUNTER);
+#ifdef CONFIG_X86_PM_TIMER
+ } else if (vxtime.mode == VXTIME_PMTMR) {
+ pmtimer_resume();
+#endif
+ } else
+ vxtime.last_tsc = get_cycles_sync();
write_sequnlock_irqrestore(&xtime_lock,flags);
jiffies += sleep_length;
wall_jiffies += sleep_length;
+ monotonic_base += sleep_length * (NSEC_PER_SEC/HZ);
touch_softlockup_watchdog();
return 0;
}
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index 8bb0aeda78b..ee1b2da9e5e 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -372,7 +372,7 @@ void out_of_line_bug(void)
static DEFINE_SPINLOCK(die_lock);
static int die_owner = -1;
-unsigned long oops_begin(void)
+unsigned __kprobes long oops_begin(void)
{
int cpu = safe_smp_processor_id();
unsigned long flags;
@@ -391,7 +391,7 @@ unsigned long oops_begin(void)
return flags;
}
-void oops_end(unsigned long flags)
+void __kprobes oops_end(unsigned long flags)
{
die_owner = -1;
bust_spinlocks(0);
@@ -400,7 +400,7 @@ void oops_end(unsigned long flags)
panic("Oops");
}
-void __die(const char * str, struct pt_regs * regs, long err)
+void __kprobes __die(const char * str, struct pt_regs * regs, long err)
{
static int die_counter;
printk(KERN_EMERG "%s: %04lx [%u] ", str, err & 0xffff,++die_counter);
@@ -432,7 +432,7 @@ void die(const char * str, struct pt_regs * regs, long err)
do_exit(SIGSEGV);
}
-void die_nmi(char *str, struct pt_regs *regs)
+void __kprobes die_nmi(char *str, struct pt_regs *regs)
{
unsigned long flags = oops_begin();
@@ -575,7 +575,8 @@ asmlinkage void __kprobes do_general_protection(struct pt_regs * regs,
}
}
-static void mem_parity_error(unsigned char reason, struct pt_regs * regs)
+static __kprobes void
+mem_parity_error(unsigned char reason, struct pt_regs * regs)
{
printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n");
printk("You probably have a hardware problem with your RAM chips\n");
@@ -585,7 +586,8 @@ static void mem_parity_error(unsigned char reason, struct pt_regs * regs)
outb(reason, 0x61);
}
-static void io_check_error(unsigned char reason, struct pt_regs * regs)
+static __kprobes void
+io_check_error(unsigned char reason, struct pt_regs * regs)
{
printk("NMI: IOCK error (debug interrupt?)\n");
show_registers(regs);
@@ -598,7 +600,8 @@ static void io_check_error(unsigned char reason, struct pt_regs * regs)
outb(reason, 0x61);
}
-static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
+static __kprobes void
+unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
{ printk("Uhhuh. NMI received for unknown reason %02x.\n", reason);
printk("Dazed and confused, but trying to continue\n");
printk("Do you have a strange power saving mode enabled?\n");
@@ -606,7 +609,7 @@ static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
/* Runs on IST stack. This code must keep interrupts off all the time.
Nested NMIs are prevented by the CPU. */
-asmlinkage void default_do_nmi(struct pt_regs *regs)
+asmlinkage __kprobes void default_do_nmi(struct pt_regs *regs)
{
unsigned char reason = 0;
int cpu;
@@ -658,7 +661,7 @@ asmlinkage void __kprobes do_int3(struct pt_regs * regs, long error_code)
/* Help handler running on IST stack to switch back to user stack
for scheduling or signal handling. The actual stack switch is done in
entry.S */
-asmlinkage struct pt_regs *sync_regs(struct pt_regs *eregs)
+asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs)
{
struct pt_regs *regs = eregs;
/* Did already sync */
diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S
index b0eed1faf74..74db0062d4a 100644
--- a/arch/x86_64/kernel/vmlinux.lds.S
+++ b/arch/x86_64/kernel/vmlinux.lds.S
@@ -172,13 +172,15 @@ SECTIONS
. = ALIGN(4096);
__initramfs_start = .;
.init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { *(.init.ramfs) }
- __initramfs_end = .;
- . = ALIGN(32);
+ __initramfs_end = .;
+ /* temporary here to work around NR_CPUS. If you see this comment in 2.6.17+
+ complain */
+ . = ALIGN(4096);
+ __init_end = .;
+ . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
__per_cpu_start = .;
.data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { *(.data.percpu) }
__per_cpu_end = .;
- . = ALIGN(4096);
- __init_end = .;
. = ALIGN(4096);
__nosave_begin = .;
diff --git a/arch/x86_64/lib/clear_page.S b/arch/x86_64/lib/clear_page.S
index 43d9fa13618..1f81b79b796 100644
--- a/arch/x86_64/lib/clear_page.S
+++ b/arch/x86_64/lib/clear_page.S
@@ -5,8 +5,46 @@
.globl clear_page
.p2align 4
clear_page:
+ xorl %eax,%eax
+ movl $4096/64,%ecx
+ .p2align 4
+.Lloop:
+ decl %ecx
+#define PUT(x) movq %rax,x*8(%rdi)
+ movq %rax,(%rdi)
+ PUT(1)
+ PUT(2)
+ PUT(3)
+ PUT(4)
+ PUT(5)
+ PUT(6)
+ PUT(7)
+ leaq 64(%rdi),%rdi
+ jnz .Lloop
+ nop
+ ret
+clear_page_end:
+
+ /* Some CPUs run faster using the string instructions.
+ It is also a lot simpler. Use this when possible */
+
+#include <asm/cpufeature.h>
+
+ .section .altinstructions,"a"
+ .align 8
+ .quad clear_page
+ .quad clear_page_c
+ .byte X86_FEATURE_REP_GOOD
+ .byte clear_page_end-clear_page
+ .byte clear_page_c_end-clear_page_c
+ .previous
+
+ .section .altinstr_replacement,"ax"
+clear_page_c:
movl $4096/8,%ecx
xorl %eax,%eax
rep
stosq
ret
+clear_page_c_end:
+ .previous
diff --git a/arch/x86_64/lib/copy_page.S b/arch/x86_64/lib/copy_page.S
index 621a1976940..8fa19d96a7e 100644
--- a/arch/x86_64/lib/copy_page.S
+++ b/arch/x86_64/lib/copy_page.S
@@ -8,7 +8,94 @@
.globl copy_page
.p2align 4
copy_page:
+ subq $3*8,%rsp
+ movq %rbx,(%rsp)
+ movq %r12,1*8(%rsp)
+ movq %r13,2*8(%rsp)
+
+ movl $(4096/64)-5,%ecx
+ .p2align 4
+.Loop64:
+ dec %rcx
+
+ movq (%rsi), %rax
+ movq 8 (%rsi), %rbx
+ movq 16 (%rsi), %rdx
+ movq 24 (%rsi), %r8
+ movq 32 (%rsi), %r9
+ movq 40 (%rsi), %r10
+ movq 48 (%rsi), %r11
+ movq 56 (%rsi), %r12
+
+ prefetcht0 5*64(%rsi)
+
+ movq %rax, (%rdi)
+ movq %rbx, 8 (%rdi)
+ movq %rdx, 16 (%rdi)
+ movq %r8, 24 (%rdi)
+ movq %r9, 32 (%rdi)
+ movq %r10, 40 (%rdi)
+ movq %r11, 48 (%rdi)
+ movq %r12, 56 (%rdi)
+
+ leaq 64 (%rsi), %rsi
+ leaq 64 (%rdi), %rdi
+
+ jnz .Loop64
+
+ movl $5,%ecx
+ .p2align 4
+.Loop2:
+ decl %ecx
+
+ movq (%rsi), %rax
+ movq 8 (%rsi), %rbx
+ movq 16 (%rsi), %rdx
+ movq 24 (%rsi), %r8
+ movq 32 (%rsi), %r9
+ movq 40 (%rsi), %r10
+ movq 48 (%rsi), %r11
+ movq 56 (%rsi), %r12
+
+ movq %rax, (%rdi)
+ movq %rbx, 8 (%rdi)
+ movq %rdx, 16 (%rdi)
+ movq %r8, 24 (%rdi)
+ movq %r9, 32 (%rdi)
+ movq %r10, 40 (%rdi)
+ movq %r11, 48 (%rdi)
+ movq %r12, 56 (%rdi)
+
+ leaq 64(%rdi),%rdi
+ leaq 64(%rsi),%rsi
+
+ jnz .Loop2
+
+ movq (%rsp),%rbx
+ movq 1*8(%rsp),%r12
+ movq 2*8(%rsp),%r13
+ addq $3*8,%rsp
+ ret
+
+ /* Some CPUs run faster using the string copy instructions.
+ It is also a lot simpler. Use this when possible */
+
+#include <asm/cpufeature.h>
+
+ .section .altinstructions,"a"
+ .align 8
+ .quad copy_page
+ .quad copy_page_c
+ .byte X86_FEATURE_REP_GOOD
+ .byte copy_page_c_end-copy_page_c
+ .byte copy_page_c_end-copy_page_c
+ .previous
+
+ .section .altinstr_replacement,"ax"
+copy_page_c:
movl $4096/8,%ecx
rep
movsq
ret
+copy_page_c_end:
+ .previous
diff --git a/arch/x86_64/lib/copy_user.S b/arch/x86_64/lib/copy_user.S
index 79422b6559c..f64569b83b5 100644
--- a/arch/x86_64/lib/copy_user.S
+++ b/arch/x86_64/lib/copy_user.S
@@ -4,9 +4,12 @@
* Functions to copy from and to user space.
*/
+#define FIX_ALIGNMENT 1
+
#include <asm/current.h>
#include <asm/asm-offsets.h>
#include <asm/thread_info.h>
+ #include <asm/cpufeature.h>
/* Standard copy_to_user with segment limit checking */
.globl copy_to_user
@@ -18,7 +21,23 @@ copy_to_user:
jc bad_to_user
cmpq threadinfo_addr_limit(%rax),%rcx
jae bad_to_user
- jmp copy_user_generic
+2:
+ .byte 0xe9 /* 32bit jump */
+ .long .Lcug-1f
+1:
+
+ .section .altinstr_replacement,"ax"
+3: .byte 0xe9 /* replacement jmp with 8 bit immediate */
+ .long copy_user_generic_c-1b /* offset */
+ .previous
+ .section .altinstructions,"a"
+ .align 8
+ .quad 2b
+ .quad 3b
+ .byte X86_FEATURE_REP_GOOD
+ .byte 5
+ .byte 5
+ .previous
/* Standard copy_from_user with segment limit checking */
.globl copy_from_user
@@ -53,44 +72,230 @@ bad_to_user:
* rsi source
* rdx count
*
- * Only 4GB of copy is supported. This shouldn't be a problem
- * because the kernel normally only writes from/to page sized chunks
- * even if user space passed a longer buffer.
- * And more would be dangerous because both Intel and AMD have
- * errata with rep movsq > 4GB. If someone feels the need to fix
- * this please consider this.
- *
* Output:
* eax uncopied bytes or 0 if successful.
*/
-
.globl copy_user_generic
+ .p2align 4
copy_user_generic:
+ .byte 0x66,0x66,0x90 /* 5 byte nop for replacement jump */
+ .byte 0x66,0x90
+1:
+ .section .altinstr_replacement,"ax"
+2: .byte 0xe9 /* near jump with 32bit immediate */
+ .long copy_user_generic_c-1b /* offset */
+ .previous
+ .section .altinstructions,"a"
+ .align 8
+ .quad copy_user_generic
+ .quad 2b
+ .byte X86_FEATURE_REP_GOOD
+ .byte 5
+ .byte 5
+ .previous
+.Lcug:
+ pushq %rbx
+ xorl %eax,%eax /*zero for the exception handler */
+
+#ifdef FIX_ALIGNMENT
+ /* check for bad alignment of destination */
+ movl %edi,%ecx
+ andl $7,%ecx
+ jnz .Lbad_alignment
+.Lafter_bad_alignment:
+#endif
+
+ movq %rdx,%rcx
+
+ movl $64,%ebx
+ shrq $6,%rdx
+ decq %rdx
+ js .Lhandle_tail
+
+ .p2align 4
+.Lloop:
+.Ls1: movq (%rsi),%r11
+.Ls2: movq 1*8(%rsi),%r8
+.Ls3: movq 2*8(%rsi),%r9
+.Ls4: movq 3*8(%rsi),%r10
+.Ld1: movq %r11,(%rdi)
+.Ld2: movq %r8,1*8(%rdi)
+.Ld3: movq %r9,2*8(%rdi)
+.Ld4: movq %r10,3*8(%rdi)
+
+.Ls5: movq 4*8(%rsi),%r11
+.Ls6: movq 5*8(%rsi),%r8
+.Ls7: movq 6*8(%rsi),%r9
+.Ls8: movq 7*8(%rsi),%r10
+.Ld5: movq %r11,4*8(%rdi)
+.Ld6: movq %r8,5*8(%rdi)
+.Ld7: movq %r9,6*8(%rdi)
+.Ld8: movq %r10,7*8(%rdi)
+
+ decq %rdx
+
+ leaq 64(%rsi),%rsi
+ leaq 64(%rdi),%rdi
+
+ jns .Lloop
+
+ .p2align 4
+.Lhandle_tail:
+ movl %ecx,%edx
+ andl $63,%ecx
+ shrl $3,%ecx
+ jz .Lhandle_7
+ movl $8,%ebx
+ .p2align 4
+.Lloop_8:
+.Ls9: movq (%rsi),%r8
+.Ld9: movq %r8,(%rdi)
+ decl %ecx
+ leaq 8(%rdi),%rdi
+ leaq 8(%rsi),%rsi
+ jnz .Lloop_8
+
+.Lhandle_7:
+ movl %edx,%ecx
+ andl $7,%ecx
+ jz .Lende
+ .p2align 4
+.Lloop_1:
+.Ls10: movb (%rsi),%bl
+.Ld10: movb %bl,(%rdi)
+ incq %rdi
+ incq %rsi
+ decl %ecx
+ jnz .Lloop_1
+
+.Lende:
+ popq %rbx
+ ret
+
+#ifdef FIX_ALIGNMENT
+ /* align destination */
+ .p2align 4
+.Lbad_alignment:
+ movl $8,%r9d
+ subl %ecx,%r9d
+ movl %r9d,%ecx
+ cmpq %r9,%rdx
+ jz .Lhandle_7
+ js .Lhandle_7
+.Lalign_1:
+.Ls11: movb (%rsi),%bl
+.Ld11: movb %bl,(%rdi)
+ incq %rsi
+ incq %rdi
+ decl %ecx
+ jnz .Lalign_1
+ subq %r9,%rdx
+ jmp .Lafter_bad_alignment
+#endif
+
+ /* table sorted by exception address */
+ .section __ex_table,"a"
+ .align 8
+ .quad .Ls1,.Ls1e
+ .quad .Ls2,.Ls2e
+ .quad .Ls3,.Ls3e
+ .quad .Ls4,.Ls4e
+ .quad .Ld1,.Ls1e
+ .quad .Ld2,.Ls2e
+ .quad .Ld3,.Ls3e
+ .quad .Ld4,.Ls4e
+ .quad .Ls5,.Ls5e
+ .quad .Ls6,.Ls6e
+ .quad .Ls7,.Ls7e
+ .quad .Ls8,.Ls8e
+ .quad .Ld5,.Ls5e
+ .quad .Ld6,.Ls6e
+ .quad .Ld7,.Ls7e
+ .quad .Ld8,.Ls8e
+ .quad .Ls9,.Le_quad
+ .quad .Ld9,.Le_quad
+ .quad .Ls10,.Le_byte
+ .quad .Ld10,.Le_byte
+#ifdef FIX_ALIGNMENT
+ .quad .Ls11,.Lzero_rest
+ .quad .Ld11,.Lzero_rest
+#endif
+ .quad .Le5,.Le_zero
+ .previous
+
+ /* compute 64-offset for main loop. 8 bytes accuracy with error on the
+ pessimistic side. this is gross. it would be better to fix the
+ interface. */
+ /* eax: zero, ebx: 64 */
+.Ls1e: addl $8,%eax
+.Ls2e: addl $8,%eax
+.Ls3e: addl $8,%eax
+.Ls4e: addl $8,%eax
+.Ls5e: addl $8,%eax
+.Ls6e: addl $8,%eax
+.Ls7e: addl $8,%eax
+.Ls8e: addl $8,%eax
+ addq %rbx,%rdi /* +64 */
+ subq %rax,%rdi /* correct destination with computed offset */
+
+ shlq $6,%rdx /* loop counter * 64 (stride length) */
+ addq %rax,%rdx /* add offset to loopcnt */
+ andl $63,%ecx /* remaining bytes */
+ addq %rcx,%rdx /* add them */
+ jmp .Lzero_rest
+
+ /* exception on quad word loop in tail handling */
+ /* ecx: loopcnt/8, %edx: length, rdi: correct */
+.Le_quad:
+ shll $3,%ecx
+ andl $7,%edx
+ addl %ecx,%edx
+ /* edx: bytes to zero, rdi: dest, eax:zero */
+.Lzero_rest:
+ movq %rdx,%rcx
+.Le_byte:
+ xorl %eax,%eax
+.Le5: rep
+ stosb
+ /* when there is another exception while zeroing the rest just return */
+.Le_zero:
+ movq %rdx,%rax
+ jmp .Lende
+
+ /* Some CPUs run faster using the string copy instructions.
+ This is also a lot simpler. Use them when possible.
+ Patch in jmps to this code instead of copying it fully
+ to avoid unwanted aliasing in the exception tables. */
+
+ /* rdi destination
+ * rsi source
+ * rdx count
+ *
+ * Output:
+ * eax uncopied bytes or 0 if successfull.
+ *
+ * Only 4GB of copy is supported. This shouldn't be a problem
+ * because the kernel normally only writes from/to page sized chunks
+ * even if user space passed a longer buffer.
+ * And more would be dangerous because both Intel and AMD have
+ * errata with rep movsq > 4GB. If someone feels the need to fix
+ * this please consider this.
+ */
+copy_user_generic_c:
movl %edx,%ecx
shrl $3,%ecx
andl $7,%edx
- jz 5f
1: rep
movsq
movl %edx,%ecx
- xor %eax,%eax
2: rep
movsb
+4: movl %ecx,%eax
ret
- /* align here? */
-5: xorl %eax,%eax
-6: rep movsq
- ret
-
- .section .fixup,"ax"
3: lea (%rdx,%rcx,8),%rax
ret
-4: movl %ecx,%eax
- ret
- .previous
.section __ex_table,"a"
.quad 1b,3b
.quad 2b,4b
- .quad 6b,4b
.previous
diff --git a/arch/x86_64/lib/memcpy.S b/arch/x86_64/lib/memcpy.S
index 92dd8054460..5554948b555 100644
--- a/arch/x86_64/lib/memcpy.S
+++ b/arch/x86_64/lib/memcpy.S
@@ -11,8 +11,6 @@
*
* Output:
* rax original destination
- *
- * TODO: check best memcpy for PSC
*/
.globl __memcpy
@@ -20,6 +18,95 @@
.p2align 4
__memcpy:
memcpy:
+ pushq %rbx
+ movq %rdi,%rax
+
+ movl %edx,%ecx
+ shrl $6,%ecx
+ jz .Lhandle_tail
+
+ .p2align 4
+.Lloop_64:
+ decl %ecx
+
+ movq (%rsi),%r11
+ movq 8(%rsi),%r8
+
+ movq %r11,(%rdi)
+ movq %r8,1*8(%rdi)
+
+ movq 2*8(%rsi),%r9
+ movq 3*8(%rsi),%r10
+
+ movq %r9,2*8(%rdi)
+ movq %r10,3*8(%rdi)
+
+ movq 4*8(%rsi),%r11
+ movq 5*8(%rsi),%r8
+
+ movq %r11,4*8(%rdi)
+ movq %r8,5*8(%rdi)
+
+ movq 6*8(%rsi),%r9
+ movq 7*8(%rsi),%r10
+
+ movq %r9,6*8(%rdi)
+ movq %r10,7*8(%rdi)
+
+ leaq 64(%rsi),%rsi
+ leaq 64(%rdi),%rdi
+ jnz .Lloop_64
+
+.Lhandle_tail:
+ movl %edx,%ecx
+ andl $63,%ecx
+ shrl $3,%ecx
+ jz .Lhandle_7
+ .p2align 4
+.Lloop_8:
+ decl %ecx
+ movq (%rsi),%r8
+ movq %r8,(%rdi)
+ leaq 8(%rdi),%rdi
+ leaq 8(%rsi),%rsi
+ jnz .Lloop_8
+
+.Lhandle_7:
+ movl %edx,%ecx
+ andl $7,%ecx
+ jz .Lende
+ .p2align 4
+.Lloop_1:
+ movb (%rsi),%r8b
+ movb %r8b,(%rdi)
+ incq %rdi
+ incq %rsi
+ decl %ecx
+ jnz .Lloop_1
+
+.Lende:
+ popq %rbx
+ ret
+.Lfinal:
+
+ /* Some CPUs run faster using the string copy instructions.
+ It is also a lot simpler. Use this when possible */
+
+ .section .altinstructions,"a"
+ .align 8
+ .quad memcpy
+ .quad memcpy_c
+ .byte X86_FEATURE_REP_GOOD
+ .byte .Lfinal-memcpy
+ .byte memcpy_c_end-memcpy_c
+ .previous
+
+ .section .altinstr_replacement,"ax"
+ /* rdi destination
+ * rsi source
+ * rdx count
+ */
+memcpy_c:
movq %rdi,%rax
movl %edx,%ecx
shrl $3,%ecx
@@ -30,3 +117,5 @@ memcpy:
rep
movsb
ret
+memcpy_c_end:
+ .previous
diff --git a/arch/x86_64/lib/memset.S b/arch/x86_64/lib/memset.S
index 2aa48f24ed1..ad397f2c7de 100644
--- a/arch/x86_64/lib/memset.S
+++ b/arch/x86_64/lib/memset.S
@@ -13,6 +13,98 @@
.p2align 4
memset:
__memset:
+ movq %rdi,%r10
+ movq %rdx,%r11
+
+ /* expand byte value */
+ movzbl %sil,%ecx
+ movabs $0x0101010101010101,%rax
+ mul %rcx /* with rax, clobbers rdx */
+
+ /* align dst */
+ movl %edi,%r9d
+ andl $7,%r9d
+ jnz .Lbad_alignment
+.Lafter_bad_alignment:
+
+ movl %r11d,%ecx
+ shrl $6,%ecx
+ jz .Lhandle_tail
+
+ .p2align 4
+.Lloop_64:
+ decl %ecx
+ movq %rax,(%rdi)
+ movq %rax,8(%rdi)
+ movq %rax,16(%rdi)
+ movq %rax,24(%rdi)
+ movq %rax,32(%rdi)
+ movq %rax,40(%rdi)
+ movq %rax,48(%rdi)
+ movq %rax,56(%rdi)
+ leaq 64(%rdi),%rdi
+ jnz .Lloop_64
+
+ /* Handle tail in loops. The loops should be faster than hard
+ to predict jump tables. */
+ .p2align 4
+.Lhandle_tail:
+ movl %r11d,%ecx
+ andl $63&(~7),%ecx
+ jz .Lhandle_7
+ shrl $3,%ecx
+ .p2align 4
+.Lloop_8:
+ decl %ecx
+ movq %rax,(%rdi)
+ leaq 8(%rdi),%rdi
+ jnz .Lloop_8
+
+.Lhandle_7:
+ movl %r11d,%ecx
+ andl $7,%ecx
+ jz .Lende
+ .p2align 4
+.Lloop_1:
+ decl %ecx
+ movb %al,(%rdi)
+ leaq 1(%rdi),%rdi
+ jnz .Lloop_1
+
+.Lende:
+ movq %r10,%rax
+ ret
+
+.Lbad_alignment:
+ cmpq $7,%r11
+ jbe .Lhandle_7
+ movq %rax,(%rdi) /* unaligned store */
+ movq $8,%r8
+ subq %r9,%r8
+ addq %r8,%rdi
+ subq %r8,%r11
+ jmp .Lafter_bad_alignment
+
+ /* Some CPUs run faster using the string instructions.
+ It is also a lot simpler. Use this when possible */
+
+#include <asm/cpufeature.h>
+
+ .section .altinstructions,"a"
+ .align 8
+ .quad memset
+ .quad memset_c
+ .byte X86_FEATURE_REP_GOOD
+ .byte memset_c_end-memset_c
+ .byte memset_c_end-memset_c
+ .previous
+
+ .section .altinstr_replacement,"ax"
+ /* rdi destination
+ * rsi value
+ * rdx count
+ */
+memset_c:
movq %rdi,%r9
movl %edx,%r8d
andl $7,%r8d
@@ -29,3 +121,5 @@ __memset:
stosb
movq %r9,%rax
ret
+memset_c_end:
+ .previous
diff --git a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c
index 26eac194064..2e7c3c8ffe0 100644
--- a/arch/x86_64/mm/fault.c
+++ b/arch/x86_64/mm/fault.c
@@ -33,7 +33,6 @@
#include <asm/proto.h>
#include <asm/kdebug.h>
#include <asm-generic/sections.h>
-#include <asm/kdebug.h>
/* Page fault error code bits */
#define PF_PROT (1<<0) /* or no page found */
@@ -157,8 +156,8 @@ void dump_pagetable(unsigned long address)
pgd = __va((unsigned long)pgd & PHYSICAL_PAGE_MASK);
pgd += pgd_index(address);
- printk("PGD %lx ", pgd_val(*pgd));
if (bad_address(pgd)) goto bad;
+ printk("PGD %lx ", pgd_val(*pgd));
if (!pgd_present(*pgd)) goto ret;
pud = __pud_offset_k((pud_t *)pgd_page(*pgd), address);
diff --git a/arch/x86_64/mm/srat.c b/arch/x86_64/mm/srat.c
index 8b7f85608fa..cd25300726f 100644
--- a/arch/x86_64/mm/srat.c
+++ b/arch/x86_64/mm/srat.c
@@ -26,6 +26,10 @@ static nodemask_t nodes_found __initdata;
static struct node nodes[MAX_NUMNODES] __initdata;
static u8 pxm2node[256] = { [0 ... 255] = 0xff };
+/* Too small nodes confuse the VM badly. Usually they result
+ from BIOS bugs. */
+#define NODE_MIN_SIZE (4*1024*1024)
+
static int node_to_pxm(int n);
int pxm_to_node(int pxm)
@@ -131,7 +135,12 @@ void __init
acpi_numa_processor_affinity_init(struct acpi_table_processor_affinity *pa)
{
int pxm, node;
- if (srat_disabled() || pa->flags.enabled == 0)
+ if (srat_disabled())
+ return;
+ if (pa->header.length != sizeof(struct acpi_table_processor_affinity)) { bad_srat();
+ return;
+ }
+ if (pa->flags.enabled == 0)
return;
pxm = pa->proximity_domain;
node = setup_node(pxm);
@@ -155,8 +164,16 @@ acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma)
int node, pxm;
int i;
- if (srat_disabled() || ma->flags.enabled == 0)
+ if (srat_disabled())
+ return;
+ if (ma->header.length != sizeof(struct acpi_table_memory_affinity)) {
+ bad_srat();
return;
+ }
+ if (ma->flags.enabled == 0)
+ return;
+ start = ma->base_addr_lo | ((u64)ma->base_addr_hi << 32);
+ end = start + (ma->length_lo | ((u64)ma->length_hi << 32));
pxm = ma->proximity_domain;
node = setup_node(pxm);
if (node < 0) {
@@ -164,8 +181,6 @@ acpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma)
bad_srat();
return;
}
- start = ma->base_addr_lo | ((u64)ma->base_addr_hi << 32);
- end = start + (ma->length_lo | ((u64)ma->length_hi << 32));
/* It is fine to add this area to the nodes data it will be used later*/
if (ma->flags.hot_pluggable == 1)
printk(KERN_INFO "SRAT: hot plug zone found %lx - %lx \n",
@@ -223,6 +238,16 @@ static int nodes_cover_memory(void)
return 1;
}
+static void unparse_node(int node)
+{
+ int i;
+ node_clear(node, nodes_parsed);
+ for (i = 0; i < MAX_LOCAL_APIC; i++) {
+ if (apicid_to_node[i] == node)
+ apicid_to_node[i] = NUMA_NO_NODE;
+ }
+}
+
void __init acpi_numa_arch_fixup(void) {}
/* Use the information discovered above to actually set up the nodes. */
@@ -230,16 +255,16 @@ int __init acpi_scan_nodes(unsigned long start, unsigned long end)
{
int i;
- if (acpi_numa <= 0)
- return -1;
-
/* First clean up the node list */
- for_each_node_mask(i, nodes_parsed) {
+ for (i = 0; i < MAX_NUMNODES; i++) {
cutoff_node(i, start, end);
- if (nodes[i].start == nodes[i].end)
- node_clear(i, nodes_parsed);
+ if ((nodes[i].end - nodes[i].start) < NODE_MIN_SIZE)
+ unparse_node(i);
}
+ if (acpi_numa <= 0)
+ return -1;
+
if (!nodes_cover_memory()) {
bad_srat();
return -1;
diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c
index 00d4ddbf980..b4a3fe4ec24 100644
--- a/arch/x86_64/pci/mmconfig.c
+++ b/arch/x86_64/pci/mmconfig.c
@@ -46,7 +46,7 @@ static char __iomem *get_virt(unsigned int seg, unsigned bus)
if (pci_mmcfg_config_num == 1 &&
cfg->pci_segment_group_number == 0 &&
(cfg->start_bus_number | cfg->end_bus_number) == 0)
- return cfg->base_address;
+ return pci_mmcfg_virt[0].virt;
/* Fall back to type 0 */
return 0;
diff --git a/arch/xtensa/platform-iss/console.c b/arch/xtensa/platform-iss/console.c
index 4fbddf92a92..94fdfe474ac 100644
--- a/arch/xtensa/platform-iss/console.c
+++ b/arch/xtensa/platform-iss/console.c
@@ -128,9 +128,7 @@ static void rs_poll(unsigned long priv)
while (__simc(SYS_select_one, 0, XTISS_SELECT_ONE_READ, (int)&tv,0,0)){
__simc (SYS_read, 0, (unsigned long)&c, 1, 0, 0);
- tty->flip.count++;
- *tty->flip.char_buf_ptr++ = c;
- *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
+ tty_insert_flip_char(tty, c, TTY_NORMAL);
i++;
}
diff --git a/block/elevator.c b/block/elevator.c
index 96a61e029ce..2fc269f6972 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -323,7 +323,8 @@ void __elv_add_request(request_queue_t *q, struct request *rq, int where,
/*
* toggle ordered color
*/
- q->ordcolor ^= 1;
+ if (blk_barrier_rq(rq))
+ q->ordcolor ^= 1;
/*
* barriers implicitly indicate back insertion
diff --git a/block/ll_rw_blk.c b/block/ll_rw_blk.c
index f9fc07efd2d..ee5ed98db4c 100644
--- a/block/ll_rw_blk.c
+++ b/block/ll_rw_blk.c
@@ -508,7 +508,7 @@ static inline struct request *start_ordered(request_queue_t *q,
int blk_do_ordered(request_queue_t *q, struct request **rqp)
{
- struct request *rq = *rqp, *allowed_rq;
+ struct request *rq = *rqp;
int is_barrier = blk_fs_request(rq) && blk_barrier_rq(rq);
if (!q->ordseq) {
@@ -532,32 +532,26 @@ int blk_do_ordered(request_queue_t *q, struct request **rqp)
}
}
+ /*
+ * Ordered sequence in progress
+ */
+
+ /* Special requests are not subject to ordering rules. */
+ if (!blk_fs_request(rq) &&
+ rq != &q->pre_flush_rq && rq != &q->post_flush_rq)
+ return 1;
+
if (q->ordered & QUEUE_ORDERED_TAG) {
+ /* Ordered by tag. Blocking the next barrier is enough. */
if (is_barrier && rq != &q->bar_rq)
*rqp = NULL;
- return 1;
- }
-
- switch (blk_ordered_cur_seq(q)) {
- case QUEUE_ORDSEQ_PREFLUSH:
- allowed_rq = &q->pre_flush_rq;
- break;
- case QUEUE_ORDSEQ_BAR:
- allowed_rq = &q->bar_rq;
- break;
- case QUEUE_ORDSEQ_POSTFLUSH:
- allowed_rq = &q->post_flush_rq;
- break;
- default:
- allowed_rq = NULL;
- break;
+ } else {
+ /* Ordered by draining. Wait for turn. */
+ WARN_ON(blk_ordered_req_seq(rq) < blk_ordered_cur_seq(q));
+ if (blk_ordered_req_seq(rq) > blk_ordered_cur_seq(q))
+ *rqp = NULL;
}
- if (rq != allowed_rq &&
- (blk_fs_request(rq) || rq == &q->pre_flush_rq ||
- rq == &q->post_flush_rq))
- *rqp = NULL;
-
return 1;
}
@@ -3453,7 +3447,7 @@ int __init blk_dev_init(void)
iocontext_cachep = kmem_cache_create("blkdev_ioc",
sizeof(struct io_context), 0, SLAB_PANIC, NULL, NULL);
- for (i = 0; i < NR_CPUS; i++)
+ for_each_cpu(i)
INIT_LIST_HEAD(&per_cpu(blk_cpu_done, i));
open_softirq(BLOCK_SOFTIRQ, blk_done_softirq, NULL);
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index be2dae52f6f..eb730a80952 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -94,7 +94,9 @@ static int set_max_cstate(struct dmi_system_id *id)
return 0;
}
-static struct dmi_system_id __initdata processor_power_dmi_table[] = {
+/* Actually this shouldn't be __cpuinitdata, would be better to fix the
+ callers to only run once -AK */
+static struct dmi_system_id __cpuinitdata processor_power_dmi_table[] = {
{ set_max_cstate, "IBM ThinkPad R40e", {
DMI_MATCH(DMI_BIOS_VENDOR,"IBM"),
DMI_MATCH(DMI_BIOS_VERSION,"1SET60WW")}, (void *)1},
@@ -899,7 +901,7 @@ static int acpi_processor_power_verify(struct acpi_processor *pr)
case ACPI_STATE_C3:
acpi_processor_power_verify_c3(pr, cx);
#ifdef ARCH_APICTIMER_STOPS_ON_C3
- if (c->x86_vendor == X86_VENDOR_INTEL) {
+ if (cx->valid && c->x86_vendor == X86_VENDOR_INTEL) {
on_each_cpu(switch_APIC_timer_to_ipi,
&mask, 1, 1);
}
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index f12898d5307..e99471d3232 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -8,6 +8,7 @@ obj-y += power/
obj-$(CONFIG_FW_LOADER) += firmware_class.o
obj-$(CONFIG_NUMA) += node.o
obj-$(CONFIG_MEMORY_HOTPLUG) += memory.o
+obj-$(CONFIG_SMP) += topology.o
ifeq ($(CONFIG_DEBUG_DRIVER),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/base/topology.c b/drivers/base/topology.c
new file mode 100644
index 00000000000..915810f6237
--- /dev/null
+++ b/drivers/base/topology.c
@@ -0,0 +1,148 @@
+/*
+ * driver/base/topology.c - Populate sysfs with cpu topology information
+ *
+ * Written by: Zhang Yanmin, Intel Corporation
+ *
+ * Copyright (C) 2006, Intel Corp.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+#include <linux/sysdev.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/cpu.h>
+#include <linux/module.h>
+#include <linux/topology.h>
+
+#define define_one_ro(_name) \
+static SYSDEV_ATTR(_name, 0444, show_##_name, NULL)
+
+#define define_id_show_func(name) \
+static ssize_t show_##name(struct sys_device *dev, char *buf) \
+{ \
+ unsigned int cpu = dev->id; \
+ return sprintf(buf, "%d\n", topology_##name(cpu)); \
+}
+
+#define define_siblings_show_func(name) \
+static ssize_t show_##name(struct sys_device *dev, char *buf) \
+{ \
+ ssize_t len = -1; \
+ unsigned int cpu = dev->id; \
+ len = cpumask_scnprintf(buf, NR_CPUS+1, topology_##name(cpu)); \
+ return (len + sprintf(buf + len, "\n")); \
+}
+
+#ifdef topology_physical_package_id
+define_id_show_func(physical_package_id);
+define_one_ro(physical_package_id);
+#define ref_physical_package_id_attr &attr_physical_package_id.attr,
+#else
+#define ref_physical_package_id_attr
+#endif
+
+#ifdef topology_core_id
+define_id_show_func(core_id);
+define_one_ro(core_id);
+#define ref_core_id_attr &attr_core_id.attr,
+#else
+#define ref_core_id_attr
+#endif
+
+#ifdef topology_thread_siblings
+define_siblings_show_func(thread_siblings);
+define_one_ro(thread_siblings);
+#define ref_thread_siblings_attr &attr_thread_siblings.attr,
+#else
+#define ref_thread_siblings_attr
+#endif
+
+#ifdef topology_core_siblings
+define_siblings_show_func(core_siblings);
+define_one_ro(core_siblings);
+#define ref_core_siblings_attr &attr_core_siblings.attr,
+#else
+#define ref_core_siblings_attr
+#endif
+
+static struct attribute *default_attrs[] = {
+ ref_physical_package_id_attr
+ ref_core_id_attr
+ ref_thread_siblings_attr
+ ref_core_siblings_attr
+ NULL
+};
+
+static struct attribute_group topology_attr_group = {
+ .attrs = default_attrs,
+ .name = "topology"
+};
+
+/* Add/Remove cpu_topology interface for CPU device */
+static int __cpuinit topology_add_dev(struct sys_device * sys_dev)
+{
+ sysfs_create_group(&sys_dev->kobj, &topology_attr_group);
+ return 0;
+}
+
+static int __cpuinit topology_remove_dev(struct sys_device * sys_dev)
+{
+ sysfs_remove_group(&sys_dev->kobj, &topology_attr_group);
+ return 0;
+}
+
+static int __cpuinit topology_cpu_callback(struct notifier_block *nfb,
+ unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned long)hcpu;
+ struct sys_device *sys_dev;
+
+ sys_dev = get_cpu_sysdev(cpu);
+ switch (action) {
+ case CPU_ONLINE:
+ topology_add_dev(sys_dev);
+ break;
+ case CPU_DEAD:
+ topology_remove_dev(sys_dev);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block topology_cpu_notifier =
+{
+ .notifier_call = topology_cpu_callback,
+};
+
+static int __cpuinit topology_sysfs_init(void)
+{
+ int i;
+
+ for_each_online_cpu(i) {
+ topology_cpu_callback(&topology_cpu_notifier, CPU_ONLINE,
+ (void *)(long)i);
+ }
+
+ register_cpu_notifier(&topology_cpu_notifier);
+
+ return 0;
+}
+
+device_initcall(topology_sysfs_init);
+
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 139cbba7618..8b133167740 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -433,12 +433,12 @@ config CDROM_PKTCDVD_BUFFERS
This controls the maximum number of active concurrent packets. More
concurrent packets can increase write performance, but also require
more memory. Each concurrent packet will require approximately 64Kb
- of non-swappable kernel memory, memory which will be allocated at
- pktsetup time.
+ of non-swappable kernel memory, memory which will be allocated when
+ a disc is opened for writing.
config CDROM_PKTCDVD_WCACHE
- bool "Enable write caching"
- depends on CDROM_PKTCDVD
+ bool "Enable write caching (EXPERIMENTAL)"
+ depends on CDROM_PKTCDVD && EXPERIMENTAL
help
If enabled, write caching will be set for the CD-R/W device. For now
this option is dangerous unless the CD-RW media is known good, as we
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 93affeeef7b..4e7dbcc425f 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -43,8 +43,6 @@
*
*************************************************************************/
-#define VERSION_CODE "v0.2.0a 2004-07-14 Jens Axboe (axboe@suse.de) and petero2@telia.com"
-
#include <linux/pktcdvd.h>
#include <linux/config.h>
#include <linux/module.h>
@@ -131,7 +129,7 @@ static struct bio *pkt_bio_alloc(int nr_iovecs)
/*
* Allocate a packet_data struct
*/
-static struct packet_data *pkt_alloc_packet_data(void)
+static struct packet_data *pkt_alloc_packet_data(int frames)
{
int i;
struct packet_data *pkt;
@@ -140,11 +138,12 @@ static struct packet_data *pkt_alloc_packet_data(void)
if (!pkt)
goto no_pkt;
- pkt->w_bio = pkt_bio_alloc(PACKET_MAX_SIZE);
+ pkt->frames = frames;
+ pkt->w_bio = pkt_bio_alloc(frames);
if (!pkt->w_bio)
goto no_bio;
- for (i = 0; i < PAGES_PER_PACKET; i++) {
+ for (i = 0; i < frames / FRAMES_PER_PAGE; i++) {
pkt->pages[i] = alloc_page(GFP_KERNEL|__GFP_ZERO);
if (!pkt->pages[i])
goto no_page;
@@ -152,7 +151,7 @@ static struct packet_data *pkt_alloc_packet_data(void)
spin_lock_init(&pkt->lock);
- for (i = 0; i < PACKET_MAX_SIZE; i++) {
+ for (i = 0; i < frames; i++) {
struct bio *bio = pkt_bio_alloc(1);
if (!bio)
goto no_rd_bio;
@@ -162,14 +161,14 @@ static struct packet_data *pkt_alloc_packet_data(void)
return pkt;
no_rd_bio:
- for (i = 0; i < PACKET_MAX_SIZE; i++) {
+ for (i = 0; i < frames; i++) {
struct bio *bio = pkt->r_bios[i];
if (bio)
bio_put(bio);
}
no_page:
- for (i = 0; i < PAGES_PER_PACKET; i++)
+ for (i = 0; i < frames / FRAMES_PER_PAGE; i++)
if (pkt->pages[i])
__free_page(pkt->pages[i]);
bio_put(pkt->w_bio);
@@ -186,12 +185,12 @@ static void pkt_free_packet_data(struct packet_data *pkt)
{
int i;
- for (i = 0; i < PACKET_MAX_SIZE; i++) {
+ for (i = 0; i < pkt->frames; i++) {
struct bio *bio = pkt->r_bios[i];
if (bio)
bio_put(bio);
}
- for (i = 0; i < PAGES_PER_PACKET; i++)
+ for (i = 0; i < pkt->frames / FRAMES_PER_PAGE; i++)
__free_page(pkt->pages[i]);
bio_put(pkt->w_bio);
kfree(pkt);
@@ -206,17 +205,17 @@ static void pkt_shrink_pktlist(struct pktcdvd_device *pd)
list_for_each_entry_safe(pkt, next, &pd->cdrw.pkt_free_list, list) {
pkt_free_packet_data(pkt);
}
+ INIT_LIST_HEAD(&pd->cdrw.pkt_free_list);
}
static int pkt_grow_pktlist(struct pktcdvd_device *pd, int nr_packets)
{
struct packet_data *pkt;
- INIT_LIST_HEAD(&pd->cdrw.pkt_free_list);
- INIT_LIST_HEAD(&pd->cdrw.pkt_active_list);
- spin_lock_init(&pd->cdrw.active_list_lock);
+ BUG_ON(!list_empty(&pd->cdrw.pkt_free_list));
+
while (nr_packets > 0) {
- pkt = pkt_alloc_packet_data();
+ pkt = pkt_alloc_packet_data(pd->settings.size >> 2);
if (!pkt) {
pkt_shrink_pktlist(pd);
return 0;
@@ -951,7 +950,7 @@ try_next_bio:
pd->current_sector = zone + pd->settings.size;
pkt->sector = zone;
- pkt->frames = pd->settings.size >> 2;
+ BUG_ON(pkt->frames != pd->settings.size >> 2);
pkt->write_size = 0;
/*
@@ -1639,7 +1638,7 @@ static int pkt_probe_settings(struct pktcdvd_device *pd)
pd->settings.size = be32_to_cpu(ti.fixed_packet_size) << 2;
if (pd->settings.size == 0) {
printk("pktcdvd: detected zero packet size!\n");
- pd->settings.size = 128;
+ return -ENXIO;
}
if (pd->settings.size > PACKET_MAX_SECTORS) {
printk("pktcdvd: packet size is too big\n");
@@ -1987,8 +1986,14 @@ static int pkt_open_dev(struct pktcdvd_device *pd, int write)
if ((ret = pkt_set_segment_merging(pd, q)))
goto out_unclaim;
- if (write)
+ if (write) {
+ if (!pkt_grow_pktlist(pd, CONFIG_CDROM_PKTCDVD_BUFFERS)) {
+ printk("pktcdvd: not enough memory for buffers\n");
+ ret = -ENOMEM;
+ goto out_unclaim;
+ }
printk("pktcdvd: %lukB available on disc\n", lba << 1);
+ }
return 0;
@@ -2014,6 +2019,8 @@ static void pkt_release_dev(struct pktcdvd_device *pd, int flush)
pkt_set_speed(pd, MAX_SPEED, MAX_SPEED);
bd_release(pd->bdev);
blkdev_put(pd->bdev);
+
+ pkt_shrink_pktlist(pd);
}
static struct pktcdvd_device *pkt_find_dev_from_minor(int dev_minor)
@@ -2379,12 +2386,6 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
/* This is safe, since we have a reference from open(). */
__module_get(THIS_MODULE);
- if (!pkt_grow_pktlist(pd, CONFIG_CDROM_PKTCDVD_BUFFERS)) {
- printk("pktcdvd: not enough memory for buffers\n");
- ret = -ENOMEM;
- goto out_mem;
- }
-
pd->bdev = bdev;
set_blocksize(bdev, CD_FRAMESIZE);
@@ -2395,7 +2396,7 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
if (IS_ERR(pd->cdrw.thread)) {
printk("pktcdvd: can't start kernel thread\n");
ret = -ENOMEM;
- goto out_thread;
+ goto out_mem;
}
proc = create_proc_entry(pd->name, 0, pkt_proc);
@@ -2406,8 +2407,6 @@ static int pkt_new_dev(struct pktcdvd_device *pd, dev_t dev)
DPRINTK("pktcdvd: writer %s mapped to %s\n", pd->name, bdevname(bdev, b));
return 0;
-out_thread:
- pkt_shrink_pktlist(pd);
out_mem:
blkdev_put(bdev);
/* This is safe: open() is still holding a reference. */
@@ -2503,6 +2502,10 @@ static int pkt_setup_dev(struct pkt_ctrl_command *ctrl_cmd)
goto out_mem;
pd->disk = disk;
+ INIT_LIST_HEAD(&pd->cdrw.pkt_free_list);
+ INIT_LIST_HEAD(&pd->cdrw.pkt_active_list);
+ spin_lock_init(&pd->cdrw.active_list_lock);
+
spin_lock_init(&pd->lock);
spin_lock_init(&pd->iosched.lock);
sprintf(pd->name, "pktcdvd%d", idx);
@@ -2567,8 +2570,6 @@ static int pkt_remove_dev(struct pkt_ctrl_command *ctrl_cmd)
blkdev_put(pd->bdev);
- pkt_shrink_pktlist(pd);
-
remove_proc_entry(pd->name, pkt_proc);
DPRINTK("pktcdvd: writer %s unmapped\n", pd->name);
@@ -2678,7 +2679,6 @@ static int __init pkt_init(void)
pkt_proc = proc_mkdir("pktcdvd", proc_root_driver);
- DPRINTK("pktcdvd: %s\n", VERSION_CODE);
return 0;
out:
diff --git a/drivers/block/umem.c b/drivers/block/umem.c
index a3614e6a68d..4ada1268b40 100644
--- a/drivers/block/umem.c
+++ b/drivers/block/umem.c
@@ -882,7 +882,7 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i
card->card_number, dev->bus->number, dev->devfn);
if (pci_set_dma_mask(dev, 0xffffffffffffffffLL) &&
- !pci_set_dma_mask(dev, 0xffffffffLL)) {
+ pci_set_dma_mask(dev, 0xffffffffLL)) {
printk(KERN_WARNING "MM%d: NO suitable DMA found\n",num_cards);
return -ENOMEM;
}
diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c
index 39c61a71176..cc7acf877dc 100644
--- a/drivers/char/cyclades.c
+++ b/drivers/char/cyclades.c
@@ -1233,7 +1233,7 @@ cyy_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
info->idle_stats.recv_idle = jiffies;
}
- schedule_delayed_work(&tty->buf.work, 1);
+ tty_schedule_flip(tty);
}
/* end of service */
cy_writeb(base_addr+(CyRIR<<index), (save_xir & 0x3f));
@@ -1606,7 +1606,7 @@ cyz_handle_rx(struct cyclades_port *info,
}
#endif
info->idle_stats.recv_idle = jiffies;
- schedule_delayed_work(&tty->buf.work, 1);
+ tty_schedule_flip(tty);
}
/* Update rx_get */
cy_writel(&buf_ctrl->rx_get, new_rx_get);
@@ -1809,7 +1809,7 @@ cyz_handle_cmd(struct cyclades_card *cinfo)
if(delta_count)
cy_sched_event(info, Cy_EVENT_DELTA_WAKEUP);
if(special_count)
- schedule_delayed_work(&tty->buf.work, 1);
+ tty_schedule_flip(tty);
}
}
diff --git a/drivers/char/drm/ati_pcigart.c b/drivers/char/drm/ati_pcigart.c
index 5485382cade..bd7be09ea53 100644
--- a/drivers/char/drm/ati_pcigart.c
+++ b/drivers/char/drm/ati_pcigart.c
@@ -59,17 +59,16 @@ static void *drm_ati_alloc_pcigart_table(void)
int i;
DRM_DEBUG("%s\n", __FUNCTION__);
- address = __get_free_pages(GFP_KERNEL, ATI_PCIGART_TABLE_ORDER);
+ address = __get_free_pages(GFP_KERNEL | __GFP_COMP,
+ ATI_PCIGART_TABLE_ORDER);
if (address == 0UL) {
- return 0;
+ return NULL;
}
page = virt_to_page(address);
- for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++) {
- get_page(page);
+ for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++)
SetPageReserved(page);
- }
DRM_DEBUG("%s: returning 0x%08lx\n", __FUNCTION__, address);
return (void *)address;
@@ -83,10 +82,8 @@ static void drm_ati_free_pcigart_table(void *address)
page = virt_to_page((unsigned long)address);
- for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++) {
- __put_page(page);
+ for (i = 0; i < ATI_PCIGART_TABLE_PAGES; i++, page++)
ClearPageReserved(page);
- }
free_pages((unsigned long)address, ATI_PCIGART_TABLE_ORDER);
}
@@ -127,7 +124,7 @@ int drm_ati_pcigart_cleanup(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
if (gart_info->gart_table_location == DRM_ATI_GART_MAIN
&& gart_info->addr) {
drm_ati_free_pcigart_table(gart_info->addr);
- gart_info->addr = 0;
+ gart_info->addr = NULL;
}
return 1;
@@ -168,7 +165,7 @@ int drm_ati_pcigart_init(drm_device_t *dev, drm_ati_pcigart_info *gart_info)
if (bus_address == 0) {
DRM_ERROR("unable to map PCIGART pages!\n");
drm_ati_free_pcigart_table(address);
- address = 0;
+ address = NULL;
goto done;
}
} else {
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index 54b561e6948..71b8b32b075 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -57,6 +57,7 @@
#include <linux/smp_lock.h> /* For (un)lock_kernel */
#include <linux/mm.h>
#include <linux/cdev.h>
+#include <linux/mutex.h>
#if defined(__alpha__) || defined(__powerpc__)
#include <asm/pgtable.h> /* For pte_wrprotect */
#endif
@@ -623,7 +624,7 @@ typedef struct drm_device {
/** \name Locks */
/*@{ */
spinlock_t count_lock; /**< For inuse, drm_device::open_count, drm_device::buf_use */
- struct semaphore struct_sem; /**< For others */
+ struct mutex struct_mutex; /**< For others */
/*@} */
/** \name Usage Counters */
@@ -658,7 +659,7 @@ typedef struct drm_device {
/*@{ */
drm_ctx_list_t *ctxlist; /**< Linked list of context handles */
int ctx_count; /**< Number of context handles */
- struct semaphore ctxlist_sem; /**< For ctxlist */
+ struct mutex ctxlist_mutex; /**< For ctxlist */
drm_map_t **context_sareas; /**< per-context SAREA's */
int max_context;
diff --git a/drivers/char/drm/drm_auth.c b/drivers/char/drm/drm_auth.c
index a47b502bc7c..2a37586a7ee 100644
--- a/drivers/char/drm/drm_auth.c
+++ b/drivers/char/drm/drm_auth.c
@@ -56,7 +56,7 @@ static int drm_hash_magic(drm_magic_t magic)
* \param magic magic number.
*
* Searches in drm_device::magiclist within all files with the same hash key
- * the one with matching magic number, while holding the drm_device::struct_sem
+ * the one with matching magic number, while holding the drm_device::struct_mutex
* lock.
*/
static drm_file_t *drm_find_file(drm_device_t * dev, drm_magic_t magic)
@@ -65,14 +65,14 @@ static drm_file_t *drm_find_file(drm_device_t * dev, drm_magic_t magic)
drm_magic_entry_t *pt;
int hash = drm_hash_magic(magic);
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
for (pt = dev->magiclist[hash].head; pt; pt = pt->next) {
if (pt->magic == magic) {
retval = pt->priv;
break;
}
}
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
return retval;
}
@@ -85,7 +85,7 @@ static drm_file_t *drm_find_file(drm_device_t * dev, drm_magic_t magic)
*
* Creates a drm_magic_entry structure and appends to the linked list
* associated the magic number hash key in drm_device::magiclist, while holding
- * the drm_device::struct_sem lock.
+ * the drm_device::struct_mutex lock.
*/
static int drm_add_magic(drm_device_t * dev, drm_file_t * priv,
drm_magic_t magic)
@@ -104,7 +104,7 @@ static int drm_add_magic(drm_device_t * dev, drm_file_t * priv,
entry->priv = priv;
entry->next = NULL;
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
if (dev->magiclist[hash].tail) {
dev->magiclist[hash].tail->next = entry;
dev->magiclist[hash].tail = entry;
@@ -112,7 +112,7 @@ static int drm_add_magic(drm_device_t * dev, drm_file_t * priv,
dev->magiclist[hash].head = entry;
dev->magiclist[hash].tail = entry;
}
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
return 0;
}
@@ -124,7 +124,7 @@ static int drm_add_magic(drm_device_t * dev, drm_file_t * priv,
* \param magic magic number.
*
* Searches and unlinks the entry in drm_device::magiclist with the magic
- * number hash key, while holding the drm_device::struct_sem lock.
+ * number hash key, while holding the drm_device::struct_mutex lock.
*/
static int drm_remove_magic(drm_device_t * dev, drm_magic_t magic)
{
@@ -135,7 +135,7 @@ static int drm_remove_magic(drm_device_t * dev, drm_magic_t magic)
DRM_DEBUG("%d\n", magic);
hash = drm_hash_magic(magic);
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
for (pt = dev->magiclist[hash].head; pt; prev = pt, pt = pt->next) {
if (pt->magic == magic) {
if (dev->magiclist[hash].head == pt) {
@@ -147,11 +147,11 @@ static int drm_remove_magic(drm_device_t * dev, drm_magic_t magic)
if (prev) {
prev->next = pt->next;
}
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
return 0;
}
}
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
drm_free(pt, sizeof(*pt), DRM_MEM_MAGIC);
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
index 1db12dcb680..e2637b4d51d 100644
--- a/drivers/char/drm/drm_bufs.c
+++ b/drivers/char/drm/drm_bufs.c
@@ -255,14 +255,14 @@ static int drm_addmap_core(drm_device_t * dev, unsigned int offset,
memset(list, 0, sizeof(*list));
list->map = map;
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
list_add(&list->head, &dev->maplist->head);
/* Assign a 32-bit handle */
- /* We do it here so that dev->struct_sem protects the increment */
+ /* We do it here so that dev->struct_mutex protects the increment */
list->user_token = HandleID(map->type == _DRM_SHM
? (unsigned long)map->handle
: map->offset, dev);
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
*maplist = list;
return 0;
@@ -392,9 +392,9 @@ int drm_rmmap(drm_device_t *dev, drm_local_map_t *map)
{
int ret;
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
ret = drm_rmmap_locked(dev, map);
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
return ret;
}
@@ -423,7 +423,7 @@ int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
return -EFAULT;
}
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
list_for_each(list, &dev->maplist->head) {
drm_map_list_t *r_list = list_entry(list, drm_map_list_t, head);
@@ -439,7 +439,7 @@ int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
* find anything.
*/
if (list == (&dev->maplist->head)) {
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
return -EINVAL;
}
@@ -448,13 +448,13 @@ int drm_rmmap_ioctl(struct inode *inode, struct file *filp,
/* Register and framebuffer maps are permanent */
if ((map->type == _DRM_REGISTERS) || (map->type == _DRM_FRAME_BUFFER)) {
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
return 0;
}
ret = drm_rmmap_locked(dev, map);
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
return ret;
}
@@ -566,16 +566,16 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request)
atomic_inc(&dev->buf_alloc);
spin_unlock(&dev->count_lock);
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
entry = &dma->bufs[order];
if (entry->buf_count) {
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
atomic_dec(&dev->buf_alloc);
return -ENOMEM; /* May only call once for each order */
}
if (count < 0 || count > 4096) {
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
atomic_dec(&dev->buf_alloc);
return -EINVAL;
}
@@ -583,7 +583,7 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request)
entry->buflist = drm_alloc(count * sizeof(*entry->buflist),
DRM_MEM_BUFS);
if (!entry->buflist) {
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
atomic_dec(&dev->buf_alloc);
return -ENOMEM;
}
@@ -616,7 +616,7 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request)
/* Set count correctly so we free the proper amount. */
entry->buf_count = count;
drm_cleanup_buf_error(dev, entry);
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
atomic_dec(&dev->buf_alloc);
return -ENOMEM;
}
@@ -638,7 +638,7 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request)
if (!temp_buflist) {
/* Free the entry because it isn't valid */
drm_cleanup_buf_error(dev, entry);
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
atomic_dec(&dev->buf_alloc);
return -ENOMEM;
}
@@ -656,7 +656,7 @@ int drm_addbufs_agp(drm_device_t * dev, drm_buf_desc_t * request)
DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count);
DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count);
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
request->count = entry->buf_count;
request->size = size;
@@ -722,16 +722,16 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
atomic_inc(&dev->buf_alloc);
spin_unlock(&dev->count_lock);
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
entry = &dma->bufs[order];
if (entry->buf_count) {
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
atomic_dec(&dev->buf_alloc);
return -ENOMEM; /* May only call once for each order */
}
if (count < 0 || count > 4096) {
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
atomic_dec(&dev->buf_alloc);
return -EINVAL;
}
@@ -739,7 +739,7 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
entry->buflist = drm_alloc(count * sizeof(*entry->buflist),
DRM_MEM_BUFS);
if (!entry->buflist) {
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
atomic_dec(&dev->buf_alloc);
return -ENOMEM;
}
@@ -750,7 +750,7 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
if (!entry->seglist) {
drm_free(entry->buflist,
count * sizeof(*entry->buflist), DRM_MEM_BUFS);
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
atomic_dec(&dev->buf_alloc);
return -ENOMEM;
}
@@ -766,7 +766,7 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
count * sizeof(*entry->buflist), DRM_MEM_BUFS);
drm_free(entry->seglist,
count * sizeof(*entry->seglist), DRM_MEM_SEGS);
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
atomic_dec(&dev->buf_alloc);
return -ENOMEM;
}
@@ -790,7 +790,7 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
drm_free(temp_pagelist,
(dma->page_count + (count << page_order))
* sizeof(*dma->pagelist), DRM_MEM_PAGES);
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
atomic_dec(&dev->buf_alloc);
return -ENOMEM;
}
@@ -831,7 +831,7 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
(count << page_order))
* sizeof(*dma->pagelist),
DRM_MEM_PAGES);
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
atomic_dec(&dev->buf_alloc);
return -ENOMEM;
}
@@ -853,7 +853,7 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
drm_free(temp_pagelist,
(dma->page_count + (count << page_order))
* sizeof(*dma->pagelist), DRM_MEM_PAGES);
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
atomic_dec(&dev->buf_alloc);
return -ENOMEM;
}
@@ -878,7 +878,7 @@ int drm_addbufs_pci(drm_device_t * dev, drm_buf_desc_t * request)
dma->page_count += entry->seg_count << page_order;
dma->byte_count += PAGE_SIZE * (entry->seg_count << page_order);
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
request->count = entry->buf_count;
request->size = size;
@@ -948,16 +948,16 @@ static int drm_addbufs_sg(drm_device_t * dev, drm_buf_desc_t * request)
atomic_inc(&dev->buf_alloc);
spin_unlock(&dev->count_lock);
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
entry = &dma->bufs[order];
if (entry->buf_count) {
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
atomic_dec(&dev->buf_alloc);
return -ENOMEM; /* May only call once for each order */
}
if (count < 0 || count > 4096) {
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
atomic_dec(&dev->buf_alloc);
return -EINVAL;
}
@@ -965,7 +965,7 @@ static int drm_addbufs_sg(drm_device_t * dev, drm_buf_desc_t * request)
entry->buflist = drm_alloc(count * sizeof(*entry->buflist),
DRM_MEM_BUFS);
if (!entry->buflist) {
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
atomic_dec(&dev->buf_alloc);
return -ENOMEM;
}
@@ -999,7 +999,7 @@ static int drm_addbufs_sg(drm_device_t * dev, drm_buf_desc_t * request)
/* Set count correctly so we free the proper amount. */
entry->buf_count = count;
drm_cleanup_buf_error(dev, entry);
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
atomic_dec(&dev->buf_alloc);
return -ENOMEM;
}
@@ -1022,7 +1022,7 @@ static int drm_addbufs_sg(drm_device_t * dev, drm_buf_desc_t * request)
if (!temp_buflist) {
/* Free the entry because it isn't valid */
drm_cleanup_buf_error(dev, entry);
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
atomic_dec(&dev->buf_alloc);
return -ENOMEM;
}
@@ -1040,7 +1040,7 @@ static int drm_addbufs_sg(drm_device_t * dev, drm_buf_desc_t * request)
DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count);
DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count);
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
request->count = entry->buf_count;
request->size = size;
@@ -1110,16 +1110,16 @@ int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request)
atomic_inc(&dev->buf_alloc);
spin_unlock(&dev->count_lock);
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
entry = &dma->bufs[order];
if (entry->buf_count) {
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
atomic_dec(&dev->buf_alloc);
return -ENOMEM; /* May only call once for each order */
}
if (count < 0 || count > 4096) {
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
atomic_dec(&dev->buf_alloc);
return -EINVAL;
}
@@ -1127,7 +1127,7 @@ int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request)
entry->buflist = drm_alloc(count * sizeof(*entry->buflist),
DRM_MEM_BUFS);
if (!entry->buflist) {
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
atomic_dec(&dev->buf_alloc);
return -ENOMEM;
}
@@ -1160,7 +1160,7 @@ int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request)
/* Set count correctly so we free the proper amount. */
entry->buf_count = count;
drm_cleanup_buf_error(dev, entry);
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
atomic_dec(&dev->buf_alloc);
return -ENOMEM;
}
@@ -1182,7 +1182,7 @@ int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request)
if (!temp_buflist) {
/* Free the entry because it isn't valid */
drm_cleanup_buf_error(dev, entry);
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
atomic_dec(&dev->buf_alloc);
return -ENOMEM;
}
@@ -1200,7 +1200,7 @@ int drm_addbufs_fb(drm_device_t * dev, drm_buf_desc_t * request)
DRM_DEBUG("dma->buf_count : %d\n", dma->buf_count);
DRM_DEBUG("entry->buf_count : %d\n", entry->buf_count);
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
request->count = entry->buf_count;
request->size = size;
diff --git a/drivers/char/drm/drm_context.c b/drivers/char/drm/drm_context.c
index f8425452694..83094c73da6 100644
--- a/drivers/char/drm/drm_context.c
+++ b/drivers/char/drm/drm_context.c
@@ -53,7 +53,7 @@
* \param ctx_handle context handle.
*
* Clears the bit specified by \p ctx_handle in drm_device::ctx_bitmap and the entry
- * in drm_device::context_sareas, while holding the drm_device::struct_sem
+ * in drm_device::context_sareas, while holding the drm_device::struct_mutex
* lock.
*/
void drm_ctxbitmap_free(drm_device_t * dev, int ctx_handle)
@@ -64,10 +64,10 @@ void drm_ctxbitmap_free(drm_device_t * dev, int ctx_handle)
goto failed;
if (ctx_handle < DRM_MAX_CTXBITMAP) {
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
clear_bit(ctx_handle, dev->ctx_bitmap);
dev->context_sareas[ctx_handle] = NULL;
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
return;
}
failed:
@@ -83,7 +83,7 @@ void drm_ctxbitmap_free(drm_device_t * dev, int ctx_handle)
*
* Find the first zero bit in drm_device::ctx_bitmap and (re)allocates
* drm_device::context_sareas to accommodate the new entry while holding the
- * drm_device::struct_sem lock.
+ * drm_device::struct_mutex lock.
*/
static int drm_ctxbitmap_next(drm_device_t * dev)
{
@@ -92,7 +92,7 @@ static int drm_ctxbitmap_next(drm_device_t * dev)
if (!dev->ctx_bitmap)
return -1;
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
bit = find_first_zero_bit(dev->ctx_bitmap, DRM_MAX_CTXBITMAP);
if (bit < DRM_MAX_CTXBITMAP) {
set_bit(bit, dev->ctx_bitmap);
@@ -113,7 +113,7 @@ static int drm_ctxbitmap_next(drm_device_t * dev)
DRM_MEM_MAPS);
if (!ctx_sareas) {
clear_bit(bit, dev->ctx_bitmap);
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
return -1;
}
dev->context_sareas = ctx_sareas;
@@ -126,16 +126,16 @@ static int drm_ctxbitmap_next(drm_device_t * dev)
DRM_MEM_MAPS);
if (!dev->context_sareas) {
clear_bit(bit, dev->ctx_bitmap);
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
return -1;
}
dev->context_sareas[bit] = NULL;
}
}
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
return bit;
}
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
return -1;
}
@@ -145,24 +145,24 @@ static int drm_ctxbitmap_next(drm_device_t * dev)
* \param dev DRM device.
*
* Allocates and initialize drm_device::ctx_bitmap and drm_device::context_sareas, while holding
- * the drm_device::struct_sem lock.
+ * the drm_device::struct_mutex lock.
*/
int drm_ctxbitmap_init(drm_device_t * dev)
{
int i;
int temp;
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
dev->ctx_bitmap = (unsigned long *)drm_alloc(PAGE_SIZE,
DRM_MEM_CTXBITMAP);
if (dev->ctx_bitmap == NULL) {
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
return -ENOMEM;
}
memset((void *)dev->ctx_bitmap, 0, PAGE_SIZE);
dev->context_sareas = NULL;
dev->max_context = -1;
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) {
temp = drm_ctxbitmap_next(dev);
@@ -178,17 +178,17 @@ int drm_ctxbitmap_init(drm_device_t * dev)
* \param dev DRM device.
*
* Frees drm_device::ctx_bitmap and drm_device::context_sareas, while holding
- * the drm_device::struct_sem lock.
+ * the drm_device::struct_mutex lock.
*/
void drm_ctxbitmap_cleanup(drm_device_t * dev)
{
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
if (dev->context_sareas)
drm_free(dev->context_sareas,
sizeof(*dev->context_sareas) *
dev->max_context, DRM_MEM_MAPS);
drm_free((void *)dev->ctx_bitmap, PAGE_SIZE, DRM_MEM_CTXBITMAP);
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
}
/*@}*/
@@ -222,15 +222,15 @@ int drm_getsareactx(struct inode *inode, struct file *filp,
if (copy_from_user(&request, argp, sizeof(request)))
return -EFAULT;
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
if (dev->max_context < 0
|| request.ctx_id >= (unsigned)dev->max_context) {
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
return -EINVAL;
}
map = dev->context_sareas[request.ctx_id];
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
request.handle = NULL;
list_for_each_entry(_entry, &dev->maplist->head, head) {
@@ -274,7 +274,7 @@ int drm_setsareactx(struct inode *inode, struct file *filp,
(drm_ctx_priv_map_t __user *) arg, sizeof(request)))
return -EFAULT;
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
list_for_each(list, &dev->maplist->head) {
r_list = list_entry(list, drm_map_list_t, head);
if (r_list->map
@@ -282,7 +282,7 @@ int drm_setsareactx(struct inode *inode, struct file *filp,
goto found;
}
bad:
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
return -EINVAL;
found:
@@ -294,7 +294,7 @@ int drm_setsareactx(struct inode *inode, struct file *filp,
if (request.ctx_id >= (unsigned)dev->max_context)
goto bad;
dev->context_sareas[request.ctx_id] = map;
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
return 0;
}
@@ -448,10 +448,10 @@ int drm_addctx(struct inode *inode, struct file *filp,
ctx_entry->handle = ctx.handle;
ctx_entry->tag = priv;
- down(&dev->ctxlist_sem);
+ mutex_lock(&dev->ctxlist_mutex);
list_add(&ctx_entry->head, &dev->ctxlist->head);
++dev->ctx_count;
- up(&dev->ctxlist_sem);
+ mutex_unlock(&dev->ctxlist_mutex);
if (copy_to_user(argp, &ctx, sizeof(ctx)))
return -EFAULT;
@@ -574,7 +574,7 @@ int drm_rmctx(struct inode *inode, struct file *filp,
drm_ctxbitmap_free(dev, ctx.handle);
}
- down(&dev->ctxlist_sem);
+ mutex_lock(&dev->ctxlist_mutex);
if (!list_empty(&dev->ctxlist->head)) {
drm_ctx_list_t *pos, *n;
@@ -586,7 +586,7 @@ int drm_rmctx(struct inode *inode, struct file *filp,
}
}
}
- up(&dev->ctxlist_sem);
+ mutex_unlock(&dev->ctxlist_mutex);
return 0;
}
diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c
index c4fa5a29582..dc6bbe8a18d 100644
--- a/drivers/char/drm/drm_drv.c
+++ b/drivers/char/drm/drm_drv.c
@@ -151,7 +151,7 @@ int drm_lastclose(drm_device_t * dev)
if (dev->irq_enabled)
drm_irq_uninstall(dev);
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
del_timer(&dev->timer);
/* Clear pid list */
@@ -231,7 +231,7 @@ int drm_lastclose(drm_device_t * dev)
dev->lock.filp = NULL;
wake_up_interruptible(&dev->lock.lock_queue);
}
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
DRM_DEBUG("lastclose completed\n");
return 0;
diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c
index 403f44a1bf0..641f7633878 100644
--- a/drivers/char/drm/drm_fops.c
+++ b/drivers/char/drm/drm_fops.c
@@ -262,7 +262,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
goto out_free;
}
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
if (!dev->file_last) {
priv->next = NULL;
priv->prev = NULL;
@@ -276,7 +276,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
dev->file_last->next = priv;
dev->file_last = priv;
}
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
#ifdef __alpha__
/*
@@ -413,7 +413,7 @@ int drm_release(struct inode *inode, struct file *filp)
drm_fasync(-1, filp, 0);
- down(&dev->ctxlist_sem);
+ mutex_lock(&dev->ctxlist_mutex);
if (dev->ctxlist && (!list_empty(&dev->ctxlist->head))) {
drm_ctx_list_t *pos, *n;
@@ -432,9 +432,9 @@ int drm_release(struct inode *inode, struct file *filp)
}
}
}
- up(&dev->ctxlist_sem);
+ mutex_unlock(&dev->ctxlist_mutex);
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
if (priv->remove_auth_on_close == 1) {
drm_file_t *temp = dev->file_first;
while (temp) {
@@ -452,7 +452,7 @@ int drm_release(struct inode *inode, struct file *filp)
} else {
dev->file_last = priv->prev;
}
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
if (dev->driver->postclose)
dev->driver->postclose(dev, priv);
diff --git a/drivers/char/drm/drm_ioctl.c b/drivers/char/drm/drm_ioctl.c
index bcd4e604d3e..555f323b8a3 100644
--- a/drivers/char/drm/drm_ioctl.c
+++ b/drivers/char/drm/drm_ioctl.c
@@ -194,9 +194,9 @@ int drm_getmap(struct inode *inode, struct file *filp,
return -EFAULT;
idx = map.offset;
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
if (idx < 0) {
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
return -EINVAL;
}
@@ -209,7 +209,7 @@ int drm_getmap(struct inode *inode, struct file *filp,
i++;
}
if (!r_list || !r_list->map) {
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
return -EINVAL;
}
@@ -219,7 +219,7 @@ int drm_getmap(struct inode *inode, struct file *filp,
map.flags = r_list->map->flags;
map.handle = (void *)(unsigned long)r_list->user_token;
map.mtrr = r_list->map->mtrr;
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
if (copy_to_user(argp, &map, sizeof(map)))
return -EFAULT;
@@ -253,11 +253,11 @@ int drm_getclient(struct inode *inode, struct file *filp,
if (copy_from_user(&client, argp, sizeof(client)))
return -EFAULT;
idx = client.idx;
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
for (i = 0, pt = dev->file_first; i < idx && pt; i++, pt = pt->next) ;
if (!pt) {
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
return -EINVAL;
}
client.auth = pt->authenticated;
@@ -265,7 +265,7 @@ int drm_getclient(struct inode *inode, struct file *filp,
client.uid = pt->uid;
client.magic = pt->magic;
client.iocs = pt->ioctl_count;
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
if (copy_to_user(argp, &client, sizeof(client)))
return -EFAULT;
@@ -292,7 +292,7 @@ int drm_getstats(struct inode *inode, struct file *filp,
memset(&stats, 0, sizeof(stats));
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
for (i = 0; i < dev->counters; i++) {
if (dev->types[i] == _DRM_STAT_LOCK)
@@ -305,7 +305,7 @@ int drm_getstats(struct inode *inode, struct file *filp,
stats.count = dev->counters;
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
if (copy_to_user((drm_stats_t __user *) arg, &stats, sizeof(stats)))
return -EFAULT;
diff --git a/drivers/char/drm/drm_irq.c b/drivers/char/drm/drm_irq.c
index b0d4b236e83..611a1173091 100644
--- a/drivers/char/drm/drm_irq.c
+++ b/drivers/char/drm/drm_irq.c
@@ -98,20 +98,20 @@ static int drm_irq_install(drm_device_t * dev)
if (dev->irq == 0)
return -EINVAL;
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
/* Driver must have been initialized */
if (!dev->dev_private) {
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
return -EINVAL;
}
if (dev->irq_enabled) {
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
return -EBUSY;
}
dev->irq_enabled = 1;
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
DRM_DEBUG("%s: irq=%d\n", __FUNCTION__, dev->irq);
@@ -135,9 +135,9 @@ static int drm_irq_install(drm_device_t * dev)
ret = request_irq(dev->irq, dev->driver->irq_handler,
sh_flags, dev->devname, dev);
if (ret < 0) {
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
dev->irq_enabled = 0;
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
return ret;
}
@@ -161,10 +161,10 @@ int drm_irq_uninstall(drm_device_t * dev)
if (!drm_core_check_feature(dev, DRIVER_HAVE_IRQ))
return -EINVAL;
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
irq_enabled = dev->irq_enabled;
dev->irq_enabled = 0;
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
if (!irq_enabled)
return -EINVAL;
diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h
index 5b1d3a04458..8fd6357a48d 100644
--- a/drivers/char/drm/drm_pciids.h
+++ b/drivers/char/drm/drm_pciids.h
@@ -3,6 +3,7 @@
Please contact dri-devel@lists.sf.net to add new cards to this list
*/
#define radeon_PCI_IDS \
+ {0x1002, 0x3150, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV350},\
{0x1002, 0x4136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS100|CHIP_IS_IGP}, \
{0x1002, 0x4137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS200|CHIP_IS_IGP}, \
{0x1002, 0x4144, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R300}, \
@@ -242,5 +243,6 @@
{0x8086, 0x2582, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x8086, 0x2592, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0x8086, 0x2772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x8086, 0x27a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0, 0, 0}
diff --git a/drivers/char/drm/drm_proc.c b/drivers/char/drm/drm_proc.c
index 6f943e3309e..362a270af0f 100644
--- a/drivers/char/drm/drm_proc.c
+++ b/drivers/char/drm/drm_proc.c
@@ -258,7 +258,7 @@ static int drm__vm_info(char *buf, char **start, off_t offset, int request,
}
/**
- * Simply calls _vm_info() while holding the drm_device::struct_sem lock.
+ * Simply calls _vm_info() while holding the drm_device::struct_mutex lock.
*/
static int drm_vm_info(char *buf, char **start, off_t offset, int request,
int *eof, void *data)
@@ -266,9 +266,9 @@ static int drm_vm_info(char *buf, char **start, off_t offset, int request,
drm_device_t *dev = (drm_device_t *) data;
int ret;
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
ret = drm__vm_info(buf, start, offset, request, eof, data);
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
return ret;
}
@@ -331,7 +331,7 @@ static int drm__queues_info(char *buf, char **start, off_t offset,
}
/**
- * Simply calls _queues_info() while holding the drm_device::struct_sem lock.
+ * Simply calls _queues_info() while holding the drm_device::struct_mutex lock.
*/
static int drm_queues_info(char *buf, char **start, off_t offset, int request,
int *eof, void *data)
@@ -339,9 +339,9 @@ static int drm_queues_info(char *buf, char **start, off_t offset, int request,
drm_device_t *dev = (drm_device_t *) data;
int ret;
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
ret = drm__queues_info(buf, start, offset, request, eof, data);
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
return ret;
}
@@ -403,7 +403,7 @@ static int drm__bufs_info(char *buf, char **start, off_t offset, int request,
}
/**
- * Simply calls _bufs_info() while holding the drm_device::struct_sem lock.
+ * Simply calls _bufs_info() while holding the drm_device::struct_mutex lock.
*/
static int drm_bufs_info(char *buf, char **start, off_t offset, int request,
int *eof, void *data)
@@ -411,9 +411,9 @@ static int drm_bufs_info(char *buf, char **start, off_t offset, int request,
drm_device_t *dev = (drm_device_t *) data;
int ret;
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
ret = drm__bufs_info(buf, start, offset, request, eof, data);
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
return ret;
}
@@ -459,7 +459,7 @@ static int drm__clients_info(char *buf, char **start, off_t offset,
}
/**
- * Simply calls _clients_info() while holding the drm_device::struct_sem lock.
+ * Simply calls _clients_info() while holding the drm_device::struct_mutex lock.
*/
static int drm_clients_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data)
@@ -467,9 +467,9 @@ static int drm_clients_info(char *buf, char **start, off_t offset,
drm_device_t *dev = (drm_device_t *) data;
int ret;
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
ret = drm__clients_info(buf, start, offset, request, eof, data);
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
return ret;
}
@@ -540,9 +540,9 @@ static int drm_vma_info(char *buf, char **start, off_t offset, int request,
drm_device_t *dev = (drm_device_t *) data;
int ret;
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
ret = drm__vma_info(buf, start, offset, request, eof, data);
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
return ret;
}
#endif
diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c
index 42d766359ca..7a9263ff300 100644
--- a/drivers/char/drm/drm_stub.c
+++ b/drivers/char/drm/drm_stub.c
@@ -61,8 +61,8 @@ static int drm_fill_in_dev(drm_device_t * dev, struct pci_dev *pdev,
spin_lock_init(&dev->count_lock);
init_timer(&dev->timer);
- sema_init(&dev->struct_sem, 1);
- sema_init(&dev->ctxlist_sem, 1);
+ mutex_init(&dev->struct_mutex);
+ mutex_init(&dev->ctxlist_mutex);
dev->pdev = pdev;
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
index 3f73aa774c8..0291cd62c69 100644
--- a/drivers/char/drm/drm_vm.c
+++ b/drivers/char/drm/drm_vm.c
@@ -188,7 +188,7 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
map = vma->vm_private_data;
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
for (pt = dev->vmalist, prev = NULL; pt; pt = next) {
next = pt->next;
if (pt->vma->vm_private_data == map)
@@ -248,7 +248,7 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
drm_free(map, sizeof(*map), DRM_MEM_MAPS);
}
}
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
}
/**
@@ -404,12 +404,12 @@ static void drm_vm_open(struct vm_area_struct *vma)
vma_entry = drm_alloc(sizeof(*vma_entry), DRM_MEM_VMAS);
if (vma_entry) {
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
vma_entry->vma = vma;
vma_entry->next = dev->vmalist;
vma_entry->pid = current->pid;
dev->vmalist = vma_entry;
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
}
}
@@ -431,7 +431,7 @@ static void drm_vm_close(struct vm_area_struct *vma)
vma->vm_start, vma->vm_end - vma->vm_start);
atomic_dec(&dev->vma_count);
- down(&dev->struct_sem);
+ mutex_lock(&dev->struct_mutex);
for (pt = dev->vmalist, prev = NULL; pt; prev = pt, pt = pt->next) {
if (pt->vma == vma) {
if (prev) {
@@ -443,7 +443,7 @@ static void drm_vm_close(struct vm_area_struct *vma)
break;
}
}
- up(&dev->struct_sem);
+ mutex_unlock(&dev->struct_mutex);
}
/**
diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
index cc1b8908687..ae0aa6d7e0b 100644
--- a/drivers/char/drm/i810_dma.c
+++ b/drivers/char/drm/i810_dma.c
@@ -958,7 +958,7 @@ static int i810_flush_queue(drm_device_t * dev)
}
/* Must be called with the lock held */
-void i810_reclaim_buffers(drm_device_t * dev, struct file *filp)
+static void i810_reclaim_buffers(drm_device_t * dev, struct file *filp)
{
drm_device_dma_t *dma = dev->dma;
int i;
diff --git a/drivers/char/drm/i810_drv.h b/drivers/char/drm/i810_drv.h
index a18b80d9192..e8cf3ff606f 100644
--- a/drivers/char/drm/i810_drv.h
+++ b/drivers/char/drm/i810_drv.h
@@ -113,8 +113,6 @@ typedef struct drm_i810_private {
} drm_i810_private_t;
/* i810_dma.c */
-extern void i810_reclaim_buffers(drm_device_t * dev, struct file *filp);
-
extern int i810_driver_dma_quiescent(drm_device_t * dev);
extern void i810_driver_reclaim_buffers_locked(drm_device_t * dev,
struct file *filp);
diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c
index 4fea32aed6d..163f2cbfe60 100644
--- a/drivers/char/drm/i830_dma.c
+++ b/drivers/char/drm/i830_dma.c
@@ -1239,7 +1239,7 @@ static int i830_flush_queue(drm_device_t * dev)
}
/* Must be called with the lock held */
-void i830_reclaim_buffers(drm_device_t * dev, struct file *filp)
+static void i830_reclaim_buffers(drm_device_t * dev, struct file *filp)
{
drm_device_dma_t *dma = dev->dma;
int i;
diff --git a/drivers/char/drm/i830_drv.h b/drivers/char/drm/i830_drv.h
index bf9075b576b..85bc5be6f91 100644
--- a/drivers/char/drm/i830_drv.h
+++ b/drivers/char/drm/i830_drv.h
@@ -123,9 +123,6 @@ typedef struct drm_i830_private {
extern drm_ioctl_desc_t i830_ioctls[];
extern int i830_max_ioctl;
-/* i830_dma.c */
-extern void i830_reclaim_buffers(drm_device_t * dev, struct file *filp);
-
/* i830_irq.c */
extern int i830_irq_emit(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
index 9140703da1b..1ff4c7ca0bf 100644
--- a/drivers/char/drm/i915_dma.c
+++ b/drivers/char/drm/i915_dma.c
@@ -344,18 +344,20 @@ static int i915_emit_cmds(drm_device_t * dev, int __user * buffer, int dwords)
int i;
RING_LOCALS;
+ if ((dwords+1) * sizeof(int) >= dev_priv->ring.Size - 8)
+ return DRM_ERR(EINVAL);
+
+ BEGIN_LP_RING(((dwords+1)&~1));
+
for (i = 0; i < dwords;) {
int cmd, sz;
if (DRM_COPY_FROM_USER_UNCHECKED(&cmd, &buffer[i], sizeof(cmd)))
return DRM_ERR(EINVAL);
-/* printk("%d/%d ", i, dwords); */
-
if ((sz = validate_cmd(cmd)) == 0 || i + sz > dwords)
return DRM_ERR(EINVAL);
- BEGIN_LP_RING(sz);
OUT_RING(cmd);
while (++i, --sz) {
@@ -365,9 +367,13 @@ static int i915_emit_cmds(drm_device_t * dev, int __user * buffer, int dwords)
}
OUT_RING(cmd);
}
- ADVANCE_LP_RING();
}
+ if (dwords & 1)
+ OUT_RING(0);
+
+ ADVANCE_LP_RING();
+
return 0;
}
@@ -401,6 +407,21 @@ static int i915_emit_box(drm_device_t * dev,
return 0;
}
+static void i915_emit_breadcrumb(drm_device_t *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ RING_LOCALS;
+
+ dev_priv->sarea_priv->last_enqueue = dev_priv->counter++;
+
+ BEGIN_LP_RING(4);
+ OUT_RING(CMD_STORE_DWORD_IDX);
+ OUT_RING(20);
+ OUT_RING(dev_priv->counter);
+ OUT_RING(0);
+ ADVANCE_LP_RING();
+}
+
static int i915_dispatch_cmdbuffer(drm_device_t * dev,
drm_i915_cmdbuffer_t * cmd)
{
@@ -429,6 +450,7 @@ static int i915_dispatch_cmdbuffer(drm_device_t * dev,
return ret;
}
+ i915_emit_breadcrumb(dev);
return 0;
}
@@ -475,12 +497,7 @@ static int i915_dispatch_batchbuffer(drm_device_t * dev,
dev_priv->sarea_priv->last_enqueue = dev_priv->counter++;
- BEGIN_LP_RING(4);
- OUT_RING(CMD_STORE_DWORD_IDX);
- OUT_RING(20);
- OUT_RING(dev_priv->counter);
- OUT_RING(0);
- ADVANCE_LP_RING();
+ i915_emit_breadcrumb(dev);
return 0;
}
@@ -657,7 +674,7 @@ static int i915_getparam(DRM_IOCTL_ARGS)
value = READ_BREADCRUMB(dev_priv);
break;
default:
- DRM_ERROR("Unkown parameter %d\n", param.param);
+ DRM_ERROR("Unknown parameter %d\n", param.param);
return DRM_ERR(EINVAL);
}
@@ -742,7 +759,8 @@ drm_ioctl_desc_t i915_ioctls[] = {
[DRM_IOCTL_NR(DRM_I915_ALLOC)] = {i915_mem_alloc, DRM_AUTH},
[DRM_IOCTL_NR(DRM_I915_FREE)] = {i915_mem_free, DRM_AUTH},
[DRM_IOCTL_NR(DRM_I915_INIT_HEAP)] = {i915_mem_init_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY},
- [DRM_IOCTL_NR(DRM_I915_CMDBUFFER)] = {i915_cmdbuffer, DRM_AUTH}
+ [DRM_IOCTL_NR(DRM_I915_CMDBUFFER)] = {i915_cmdbuffer, DRM_AUTH},
+ [DRM_IOCTL_NR(DRM_I915_DESTROY_HEAP)] = { i915_mem_destroy_heap, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY }
};
int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
diff --git a/drivers/char/drm/i915_drm.h b/drivers/char/drm/i915_drm.h
index 77412ddac00..4cb3da57833 100644
--- a/drivers/char/drm/i915_drm.h
+++ b/drivers/char/drm/i915_drm.h
@@ -74,6 +74,30 @@ typedef struct _drm_i915_sarea {
int pf_active;
int pf_current_page; /* which buffer is being displayed? */
int perf_boxes; /* performance boxes to be displayed */
+ int width, height; /* screen size in pixels */
+
+ drm_handle_t front_handle;
+ int front_offset;
+ int front_size;
+
+ drm_handle_t back_handle;
+ int back_offset;
+ int back_size;
+
+ drm_handle_t depth_handle;
+ int depth_offset;
+ int depth_size;
+
+ drm_handle_t tex_handle;
+ int tex_offset;
+ int tex_size;
+ int log_tex_granularity;
+ int pitch;
+ int rotation; /* 0, 90, 180 or 270 */
+ int rotated_offset;
+ int rotated_size;
+ int rotated_pitch;
+ int virtualX, virtualY;
} drm_i915_sarea_t;
/* Flags for perf_boxes
@@ -99,6 +123,7 @@ typedef struct _drm_i915_sarea {
#define DRM_I915_FREE 0x09
#define DRM_I915_INIT_HEAP 0x0a
#define DRM_I915_CMDBUFFER 0x0b
+#define DRM_I915_DESTROY_HEAP 0x0c
#define DRM_IOCTL_I915_INIT DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
#define DRM_IOCTL_I915_FLUSH DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
@@ -112,6 +137,7 @@ typedef struct _drm_i915_sarea {
#define DRM_IOCTL_I915_FREE DRM_IOW( DRM_COMMAND_BASE + DRM_I915_FREE, drm_i915_mem_free_t)
#define DRM_IOCTL_I915_INIT_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT_HEAP, drm_i915_mem_init_heap_t)
#define DRM_IOCTL_I915_CMDBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_I915_CMDBUFFER, drm_i915_cmdbuffer_t)
+#define DRM_IOCTL_I915_DESTROY_HEAP DRM_IOW( DRM_COMMAND_BASE + DRM_I915_DESTROY_HEAP, drm_i915_mem_destroy_heap_t)
/* Allow drivers to submit batchbuffers directly to hardware, relying
* on the security mechanisms provided by hardware.
@@ -191,4 +217,11 @@ typedef struct drm_i915_mem_init_heap {
int start;
} drm_i915_mem_init_heap_t;
+/* Allow memory manager to be torn down and re-initialized (eg on
+ * rotate):
+ */
+typedef struct drm_i915_mem_destroy_heap {
+ int region;
+} drm_i915_mem_destroy_heap_t;
+
#endif /* _I915_DRM_H_ */
diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h
index c6c71b45f10..7a65666899e 100644
--- a/drivers/char/drm/i915_drv.h
+++ b/drivers/char/drm/i915_drv.h
@@ -37,16 +37,17 @@
#define DRIVER_NAME "i915"
#define DRIVER_DESC "Intel Graphics"
-#define DRIVER_DATE "20051209"
+#define DRIVER_DATE "20060119"
/* Interface history:
*
* 1.1: Original.
* 1.2: Add Power Management
* 1.3: Add vblank support
+ * 1.4: Fix cmdbuffer path, add heap destroy
*/
#define DRIVER_MAJOR 1
-#define DRIVER_MINOR 3
+#define DRIVER_MINOR 4
#define DRIVER_PATCHLEVEL 0
typedef struct _drm_i915_ring_buffer {
@@ -123,6 +124,7 @@ extern void i915_driver_irq_uninstall(drm_device_t * dev);
extern int i915_mem_alloc(DRM_IOCTL_ARGS);
extern int i915_mem_free(DRM_IOCTL_ARGS);
extern int i915_mem_init_heap(DRM_IOCTL_ARGS);
+extern int i915_mem_destroy_heap(DRM_IOCTL_ARGS);
extern void i915_mem_takedown(struct mem_block **heap);
extern void i915_mem_release(drm_device_t * dev,
DRMFILE filp, struct mem_block *heap);
diff --git a/drivers/char/drm/i915_mem.c b/drivers/char/drm/i915_mem.c
index ba87ff17ff6..52c67324df5 100644
--- a/drivers/char/drm/i915_mem.c
+++ b/drivers/char/drm/i915_mem.c
@@ -365,3 +365,34 @@ int i915_mem_init_heap(DRM_IOCTL_ARGS)
return init_heap(heap, initheap.start, initheap.size);
}
+
+int i915_mem_destroy_heap( DRM_IOCTL_ARGS )
+{
+ DRM_DEVICE;
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ drm_i915_mem_destroy_heap_t destroyheap;
+ struct mem_block **heap;
+
+ if ( !dev_priv ) {
+ DRM_ERROR( "%s called with no initialization\n", __FUNCTION__ );
+ return DRM_ERR(EINVAL);
+ }
+
+ DRM_COPY_FROM_USER_IOCTL( destroyheap, (drm_i915_mem_destroy_heap_t *)data,
+ sizeof(destroyheap) );
+
+ heap = get_heap( dev_priv, destroyheap.region );
+ if (!heap) {
+ DRM_ERROR("get_heap failed");
+ return DRM_ERR(EFAULT);
+ }
+
+ if (!*heap) {
+ DRM_ERROR("heap not initialized?");
+ return DRM_ERR(EFAULT);
+ }
+
+ i915_mem_takedown( heap );
+ return 0;
+}
+
diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c
index 915665c7fe7..9bb8ae0c1c2 100644
--- a/drivers/char/drm/radeon_cp.c
+++ b/drivers/char/drm/radeon_cp.c
@@ -1640,7 +1640,7 @@ static int radeon_do_cleanup_cp(drm_device_t * dev)
if (dev_priv->gart_info.gart_table_location == DRM_ATI_GART_FB)
{
drm_core_ioremapfree(&dev_priv->gart_info.mapping, dev);
- dev_priv->gart_info.addr = 0;
+ dev_priv->gart_info.addr = NULL;
}
}
/* only clear to the start of flags */
diff --git a/drivers/char/drm/savage_bci.c b/drivers/char/drm/savage_bci.c
index 0d426deeefe..59c7520bf9a 100644
--- a/drivers/char/drm/savage_bci.c
+++ b/drivers/char/drm/savage_bci.c
@@ -32,6 +32,8 @@
#define SAVAGE_EVENT_USEC_TIMEOUT 5000000 /* 5s */
#define SAVAGE_FREELIST_DEBUG 0
+static int savage_do_cleanup_bci(drm_device_t *dev);
+
static int
savage_bci_wait_fifo_shadow(drm_savage_private_t * dev_priv, unsigned int n)
{
@@ -895,7 +897,7 @@ static int savage_do_init_bci(drm_device_t * dev, drm_savage_init_t * init)
return 0;
}
-int savage_do_cleanup_bci(drm_device_t * dev)
+static int savage_do_cleanup_bci(drm_device_t * dev)
{
drm_savage_private_t *dev_priv = dev->dev_private;
diff --git a/drivers/char/drm/savage_drv.h b/drivers/char/drm/savage_drv.h
index dd46cb85439..8f04b3d8229 100644
--- a/drivers/char/drm/savage_drv.h
+++ b/drivers/char/drm/savage_drv.h
@@ -212,7 +212,6 @@ extern int savage_driver_load(drm_device_t *dev, unsigned long chipset);
extern int savage_driver_firstopen(drm_device_t *dev);
extern void savage_driver_lastclose(drm_device_t *dev);
extern int savage_driver_unload(drm_device_t *dev);
-extern int savage_do_cleanup_bci(drm_device_t * dev);
extern void savage_reclaim_buffers(drm_device_t * dev, DRMFILE filp);
/* state functions */
diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c
index 593c0b8f650..a691ae74129 100644
--- a/drivers/char/drm/via_dma.c
+++ b/drivers/char/drm/via_dma.c
@@ -222,7 +222,7 @@ static int via_initialize(drm_device_t * dev,
return 0;
}
-int via_dma_init(DRM_IOCTL_ARGS)
+static int via_dma_init(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
@@ -321,7 +321,7 @@ int via_driver_dma_quiescent(drm_device_t * dev)
return 0;
}
-int via_flush_ioctl(DRM_IOCTL_ARGS)
+static int via_flush_ioctl(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
@@ -330,7 +330,7 @@ int via_flush_ioctl(DRM_IOCTL_ARGS)
return via_driver_dma_quiescent(dev);
}
-int via_cmdbuffer(DRM_IOCTL_ARGS)
+static int via_cmdbuffer(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_via_cmdbuffer_t cmdbuf;
@@ -375,7 +375,7 @@ static int via_dispatch_pci_cmdbuffer(drm_device_t * dev,
return ret;
}
-int via_pci_cmdbuffer(DRM_IOCTL_ARGS)
+static int via_pci_cmdbuffer(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_via_cmdbuffer_t cmdbuf;
@@ -665,7 +665,7 @@ static void via_cmdbuf_reset(drm_via_private_t * dev_priv)
* User interface to the space and lag functions.
*/
-int via_cmdbuf_size(DRM_IOCTL_ARGS)
+static int via_cmdbuf_size(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_via_cmdbuf_size_t d_siz;
diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c
index 9d5e027dae0..b7f17457b42 100644
--- a/drivers/char/drm/via_dmablit.c
+++ b/drivers/char/drm/via_dmablit.c
@@ -108,7 +108,7 @@ via_map_blit_for_device(struct pci_dev *pdev,
int num_desc = 0;
int cur_line;
dma_addr_t next = 0 | VIA_DMA_DPR_EC;
- drm_via_descriptor_t *desc_ptr = 0;
+ drm_via_descriptor_t *desc_ptr = NULL;
if (mode == 1)
desc_ptr = vsg->desc_pages[cur_descriptor_page];
@@ -167,7 +167,7 @@ via_map_blit_for_device(struct pci_dev *pdev,
*/
-void
+static void
via_free_sg_info(struct pci_dev *pdev, drm_via_sg_info_t *vsg)
{
struct page *page;
@@ -581,7 +581,7 @@ via_build_sg_info(drm_device_t *dev, drm_via_sg_info_t *vsg, drm_via_dmablit_t *
int ret = 0;
vsg->direction = (draw) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
- vsg->bounce_buffer = 0;
+ vsg->bounce_buffer = NULL;
vsg->state = dr_via_sg_init;
diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h
index aad4f99f540..52bcc7b1ba4 100644
--- a/drivers/char/drm/via_drv.h
+++ b/drivers/char/drm/via_drv.h
@@ -110,11 +110,6 @@ extern int via_mem_free(DRM_IOCTL_ARGS);
extern int via_agp_init(DRM_IOCTL_ARGS);
extern int via_map_init(DRM_IOCTL_ARGS);
extern int via_decoder_futex(DRM_IOCTL_ARGS);
-extern int via_dma_init(DRM_IOCTL_ARGS);
-extern int via_cmdbuffer(DRM_IOCTL_ARGS);
-extern int via_flush_ioctl(DRM_IOCTL_ARGS);
-extern int via_pci_cmdbuffer(DRM_IOCTL_ARGS);
-extern int via_cmdbuf_size(DRM_IOCTL_ARGS);
extern int via_wait_irq(DRM_IOCTL_ARGS);
extern int via_dma_blit_sync( DRM_IOCTL_ARGS );
extern int via_dma_blit( DRM_IOCTL_ARGS );
@@ -139,8 +134,6 @@ extern int via_driver_dma_quiescent(drm_device_t * dev);
extern void via_init_futex(drm_via_private_t * dev_priv);
extern void via_cleanup_futex(drm_via_private_t * dev_priv);
extern void via_release_futex(drm_via_private_t * dev_priv, int context);
-extern int via_driver_irq_wait(drm_device_t * dev, unsigned int irq,
- int force_sequence, unsigned int *sequence);
extern void via_dmablit_handler(drm_device_t *dev, int engine, int from_irq);
extern void via_init_dmablit(drm_device_t *dev);
diff --git a/drivers/char/drm/via_irq.c b/drivers/char/drm/via_irq.c
index 56d7e3daea1..6152415644e 100644
--- a/drivers/char/drm/via_irq.c
+++ b/drivers/char/drm/via_irq.c
@@ -190,7 +190,7 @@ int via_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
return ret;
}
-int
+static int
via_driver_irq_wait(drm_device_t * dev, unsigned int irq, int force_sequence,
unsigned int *sequence)
{
diff --git a/drivers/char/esp.c b/drivers/char/esp.c
index 3f3ac039f4d..57539d8f9f7 100644
--- a/drivers/char/esp.c
+++ b/drivers/char/esp.c
@@ -359,7 +359,7 @@ static inline void receive_chars_pio(struct esp_struct *info, int num_bytes)
}
}
- schedule_delayed_work(&tty->buf.work, 1);
+ tty_schedule_flip(tty);
info->stat_flags &= ~ESP_STAT_RX_TIMEOUT;
release_pio_buffer(pio_buf);
@@ -426,7 +426,7 @@ static inline void receive_chars_dma_done(struct esp_struct *info,
}
tty_insert_flip_char(tty, dma_buffer[num_bytes - 1], statflag);
}
- schedule_delayed_work(&tty->buf.work, 1);
+ tty_schedule_flip(tty);
}
if (dma_bytes != num_bytes) {
diff --git a/drivers/char/ip2/i2cmd.c b/drivers/char/ip2/i2cmd.c
index cb8f4198e9a..e7af647800b 100644
--- a/drivers/char/ip2/i2cmd.c
+++ b/drivers/char/ip2/i2cmd.c
@@ -139,7 +139,6 @@ static UCHAR ct79[] = { 2, BYP, 0x4F,0 }; // XMIT_NOW
//static UCHAR ct86[]={ 2, BTH, 0x56,0 }; // RCV_ENABLE
static UCHAR ct87[] = { 1, BYP, 0x57 }; // HW_TEST
//static UCHAR ct88[]={ 3, BTH, 0x58,0,0 }; // RCV_THRESHOLD
-static UCHAR ct89[]={ 1, BYP, 0x59 }; // DSS_NOW
//static UCHAR ct90[]={ 3, BYP, 0x5A,0,0 }; // Set SILO
//static UCHAR ct91[]={ 2, BYP, 0x5B,0 }; // timed break
diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c
index 56e93a5a1e2..48fcfba37bf 100644
--- a/drivers/char/ip2main.c
+++ b/drivers/char/ip2main.c
@@ -2906,65 +2906,16 @@ ip2_ipl_ioctl ( struct inode *pInode, struct file *pFile, UINT cmd, ULONG arg )
rc = -EINVAL;
break;
case 3: // Trace device
- if ( cmd == 1 ) {
- rc = put_user(iiSendPendingMail, pIndex++ );
- rc = put_user(i2InitChannels, pIndex++ );
- rc = put_user(i2QueueNeeds, pIndex++ );
- rc = put_user(i2QueueCommands, pIndex++ );
- rc = put_user(i2GetStatus, pIndex++ );
- rc = put_user(i2Input, pIndex++ );
- rc = put_user(i2InputFlush, pIndex++ );
- rc = put_user(i2Output, pIndex++ );
- rc = put_user(i2FlushOutput, pIndex++ );
- rc = put_user(i2DrainWakeup, pIndex++ );
- rc = put_user(i2DrainOutput, pIndex++ );
- rc = put_user(i2OutputFree, pIndex++ );
- rc = put_user(i2StripFifo, pIndex++ );
- rc = put_user(i2StuffFifoBypass, pIndex++ );
- rc = put_user(i2StuffFifoFlow, pIndex++ );
- rc = put_user(i2StuffFifoInline, pIndex++ );
- rc = put_user(i2ServiceBoard, pIndex++ );
- rc = put_user(serviceOutgoingFifo, pIndex++ );
- // rc = put_user(ip2_init, pIndex++ );
- rc = put_user(ip2_init_board, pIndex++ );
- rc = put_user(find_eisa_board, pIndex++ );
- rc = put_user(set_irq, pIndex++ );
- rc = put_user(ip2_interrupt, pIndex++ );
- rc = put_user(ip2_poll, pIndex++ );
- rc = put_user(service_all_boards, pIndex++ );
- rc = put_user(do_input, pIndex++ );
- rc = put_user(do_status, pIndex++ );
-#ifndef IP2DEBUG_OPEN
- rc = put_user(0, pIndex++ );
-#else
- rc = put_user(open_sanity_check, pIndex++ );
-#endif
- rc = put_user(ip2_open, pIndex++ );
- rc = put_user(ip2_close, pIndex++ );
- rc = put_user(ip2_hangup, pIndex++ );
- rc = put_user(ip2_write, pIndex++ );
- rc = put_user(ip2_putchar, pIndex++ );
- rc = put_user(ip2_flush_chars, pIndex++ );
- rc = put_user(ip2_write_room, pIndex++ );
- rc = put_user(ip2_chars_in_buf, pIndex++ );
- rc = put_user(ip2_flush_buffer, pIndex++ );
-
- //rc = put_user(ip2_wait_until_sent, pIndex++ );
- rc = put_user(0, pIndex++ );
-
- rc = put_user(ip2_throttle, pIndex++ );
- rc = put_user(ip2_unthrottle, pIndex++ );
- rc = put_user(ip2_ioctl, pIndex++ );
- rc = put_user(0, pIndex++ );
- rc = put_user(get_serial_info, pIndex++ );
- rc = put_user(set_serial_info, pIndex++ );
- rc = put_user(ip2_set_termios, pIndex++ );
- rc = put_user(ip2_set_line_discipline, pIndex++ );
- rc = put_user(set_params, pIndex++ );
- } else {
+ /*
+ * akpm: This used to write a whole bunch of function addresses
+ * to userspace, which generated lots of put_user() warnings.
+ * I killed it all. Just return "success" and don't do
+ * anything.
+ */
+ if (cmd == 1)
+ rc = 0;
+ else
rc = -EINVAL;
- }
-
break;
default:
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 0097f06fa67..d745004281d 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -481,7 +481,7 @@ int ipmi_validate_addr(struct ipmi_addr *addr, int len)
}
if ((addr->channel == IPMI_BMC_CHANNEL)
- || (addr->channel >= IPMI_NUM_CHANNELS)
+ || (addr->channel >= IPMI_MAX_CHANNELS)
|| (addr->channel < 0))
return -EINVAL;
@@ -1321,7 +1321,7 @@ static int i_ipmi_request(ipmi_user_t user,
unsigned char ipmb_seq;
long seqid;
- if (addr->channel >= IPMI_NUM_CHANNELS) {
+ if (addr->channel >= IPMI_MAX_CHANNELS) {
spin_lock_irqsave(&intf->counter_lock, flags);
intf->sent_invalid_commands++;
spin_unlock_irqrestore(&intf->counter_lock, flags);
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 6ed213bd702..e59b638766e 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -1270,36 +1270,36 @@ static int try_init_port(int intf_num, struct smi_info **new_info)
return 0;
}
-static unsigned char mem_inb(struct si_sm_io *io, unsigned int offset)
+static unsigned char intf_mem_inb(struct si_sm_io *io, unsigned int offset)
{
return readb((io->addr)+(offset * io->regspacing));
}
-static void mem_outb(struct si_sm_io *io, unsigned int offset,
+static void intf_mem_outb(struct si_sm_io *io, unsigned int offset,
unsigned char b)
{
writeb(b, (io->addr)+(offset * io->regspacing));
}
-static unsigned char mem_inw(struct si_sm_io *io, unsigned int offset)
+static unsigned char intf_mem_inw(struct si_sm_io *io, unsigned int offset)
{
return (readw((io->addr)+(offset * io->regspacing)) >> io->regshift)
&& 0xff;
}
-static void mem_outw(struct si_sm_io *io, unsigned int offset,
+static void intf_mem_outw(struct si_sm_io *io, unsigned int offset,
unsigned char b)
{
writeb(b << io->regshift, (io->addr)+(offset * io->regspacing));
}
-static unsigned char mem_inl(struct si_sm_io *io, unsigned int offset)
+static unsigned char intf_mem_inl(struct si_sm_io *io, unsigned int offset)
{
return (readl((io->addr)+(offset * io->regspacing)) >> io->regshift)
&& 0xff;
}
-static void mem_outl(struct si_sm_io *io, unsigned int offset,
+static void intf_mem_outl(struct si_sm_io *io, unsigned int offset,
unsigned char b)
{
writel(b << io->regshift, (io->addr)+(offset * io->regspacing));
@@ -1349,16 +1349,16 @@ static int mem_setup(struct smi_info *info)
upon the register size. */
switch (info->io.regsize) {
case 1:
- info->io.inputb = mem_inb;
- info->io.outputb = mem_outb;
+ info->io.inputb = intf_mem_inb;
+ info->io.outputb = intf_mem_outb;
break;
case 2:
- info->io.inputb = mem_inw;
- info->io.outputb = mem_outw;
+ info->io.inputb = intf_mem_inw;
+ info->io.outputb = intf_mem_outw;
break;
case 4:
- info->io.inputb = mem_inl;
- info->io.outputb = mem_outl;
+ info->io.inputb = intf_mem_inl;
+ info->io.outputb = intf_mem_outl;
break;
#ifdef readq
case 8:
diff --git a/drivers/char/rio/cirrus.h b/drivers/char/rio/cirrus.h
index 217ff09f2fa..89bd94eb45b 100644
--- a/drivers/char/rio/cirrus.h
+++ b/drivers/char/rio/cirrus.h
@@ -40,148 +40,6 @@
#endif
#define _cirrus_h 1
-#ifdef RTA
-#define TO_UART RX
-#define TO_DRIVER TX
-#endif
-
-#ifdef HOST
-#define TO_UART TX
-#define TO_DRIVER RX
-#endif
-#ifdef RTA
-/* Miscellaneous defines for CIRRUS addresses and related logic for
- interrupts etc.
-*/
-#define MAP(a) ((short *)(cirrus_base + (a)))
-#define outp(a,b) (*MAP (a) =(b))
-#define inp(a) ((*MAP (a)) & 0xff)
-#define CIRRUS_FIRST (short*)0x7300
-#define CIRRUS_SECOND (short*)0x7200
-#define CIRRUS_THIRD (short*)0x7100
-#define CIRRUS_FOURTH (short*)0x7000
-#define PORTS_ON_CIRRUS 4
-#define CIRRUS_FIFO_SIZE 12
-#define SPACE 0x20
-#define TAB 0x09
-#define LINE_FEED 0x0a
-#define CARRIAGE_RETURN 0x0d
-#define BACKSPACE 0x08
-#define SPACES_IN_TABS 8
-#define SEND_ESCAPE 0x00
-#define START_BREAK 0x81
-#define TIMER_TICK 0x82
-#define STOP_BREAK 0x83
-#define BASE(a) ((a) < 4 ? (short*)CIRRUS_FIRST : ((a) < 8 ? (short *)CIRRUS_SECOND : ((a) < 12 ? (short*)CIRRUS_THIRD : (short *)CIRRUS_FOURTH)))
-#define txack1 ((short *)0x7104)
-#define rxack1 ((short *)0x7102)
-#define mdack1 ((short *)0x7106)
-#define txack2 ((short *)0x7006)
-#define rxack2 ((short *)0x7004)
-#define mdack2 ((short *)0x7100)
-#define int_latch ((short *) 0x7800)
-#define int_status ((short *) 0x7c00)
-#define tx1_pending 0x20
-#define rx1_pending 0x10
-#define md1_pending 0x40
-#define tx2_pending 0x02
-#define rx2_pending 0x01
-#define md2_pending 0x40
-#define module1_bits 0x07
-#define module1_modern 0x08
-#define module2_bits 0x70
-#define module2_modern 0x80
-#define module_blank 0xf
-#define rs232_d25 0x0
-#define rs232_rj45 0x1
-#define rs422_d25 0x3
-#define parallel 0x5
-
-#define CLK0 0x00
-#define CLK1 0x01
-#define CLK2 0x02
-#define CLK3 0x03
-#define CLK4 0x04
-
-#define CIRRUS_REVC 0x42
-#define CIRRUS_REVE 0x44
-
-#define TURNON 1
-#define TURNOFF 0
-
-/* The list of CIRRUS registers.
- NB. These registers are relative values on 8 bit boundaries whereas
- on the RTA's the CIRRUS registers are on word boundaries. Use pointer
- arithmetic (short *) to obtain the real addresses required */
-#define ccr 0x05 /* Channel Command Register */
-#define ier 0x06 /* Interrupt Enable Register */
-#define cor1 0x08 /* Channel Option Register 1 */
-#define cor2 0x09 /* Channel Option Register 2 */
-#define cor3 0x0a /* Channel Option Register 3 */
-#define cor4 0x1e /* Channel Option Register 4 */
-#define cor5 0x1f /* Channel Option Register 5 */
-
-#define ccsr 0x0b /* Channel Control Status Register */
-#define rdcr 0x0e /* Receive Data Count Register */
-#define tdcr 0x12 /* Transmit Data Count Register */
-#define mcor1 0x15 /* Modem Change Option Register 1 */
-#define mcor2 0x16 /* Modem Change Option Regsiter 2 */
-
-#define livr 0x18 /* Local Interrupt Vector Register */
-#define schr1 0x1a /* Special Character Register 1 */
-#define schr2 0x1b /* Special Character Register 2 */
-#define schr3 0x1c /* Special Character Register 3 */
-#define schr4 0x1d /* Special Character Register 4 */
-
-#define rtr 0x20 /* Receive Timer Register */
-#define rtpr 0x21 /* Receive Timeout Period Register */
-#define lnc 0x24 /* Lnext character */
-
-#define rivr 0x43 /* Receive Interrupt Vector Register */
-#define tivr 0x42 /* Transmit Interrupt Vector Register */
-#define mivr 0x41 /* Modem Interrupt Vector Register */
-#define gfrcr 0x40 /* Global Firmware Revision code Reg */
-#define ricr 0x44 /* Receive Interrupting Channel Reg */
-#define ticr 0x45 /* Transmit Interrupting Channel Reg */
-#define micr 0x46 /* Modem Interrupting Channel Register */
-
-#define gcr 0x4b /* Global configuration register */
-#define misr 0x4c /* Modem interrupt status register */
-
-#define rbusr 0x59
-#define tbusr 0x5a
-#define mbusr 0x5b
-
-#define eoir 0x60 /* End Of Interrupt Register */
-#define rdsr 0x62 /* Receive Data / Status Register */
-#define tdr 0x63 /* Transmit Data Register */
-#define svrr 0x67 /* Service Request Register */
-
-#define car 0x68 /* Channel Access Register */
-#define mir 0x69 /* Modem Interrupt Register */
-#define tir 0x6a /* Transmit Interrupt Register */
-#define rir 0x6b /* Receive Interrupt Register */
-#define msvr1 0x6c /* Modem Signal Value Register 1 */
-#define msvr2 0x6d /* Modem Signal Value Register 2 */
-#define psvr 0x6f /* Printer Signal Value Register */
-
-#define tbpr 0x72 /* Transmit Baud Rate Period Register */
-#define tcor 0x76 /* Transmit Clock Option Register */
-
-#define rbpr 0x78 /* Receive Baud Rate Period Register */
-#define rber 0x7a /* Receive Baud Rate Extension Register */
-#define rcor 0x7c /* Receive Clock Option Register */
-#define ppr 0x7e /* Prescalar Period Register */
-
-/* Misc registers used for forcing the 1400 out of its reset woes */
-#define airl 0x6d
-#define airm 0x6e
-#define airh 0x6f
-#define btcr 0x66
-#define mtcr 0x6c
-#define tber 0x74
-
-#endif /* #ifdef RTA */
/* Bit fields for particular registers */
diff --git a/drivers/char/rio/defaults.h b/drivers/char/rio/defaults.h
index 5b600c32ac0..d55c2f6a987 100644
--- a/drivers/char/rio/defaults.h
+++ b/drivers/char/rio/defaults.h
@@ -45,13 +45,6 @@ static char *_rio_defaults_h_sccs = "@(#)defaults.h 1.1";
#define MILLISECOND (int) (1000/64) /* 15.625 low ticks */
#define SECOND (int) 15625 /* Low priority ticks */
-#ifdef RTA
-#define RX_LIMIT (ushort) 3
-#endif
-#ifdef HOST
-#define RX_LIMIT (ushort) 1
-#endif
-
#define LINK_TIMEOUT (int) (POLL_PERIOD / 2)
diff --git a/drivers/char/rio/link.h b/drivers/char/rio/link.h
index bfba5b0c033..48d68ca7f82 100644
--- a/drivers/char/rio/link.h
+++ b/drivers/char/rio/link.h
@@ -102,30 +102,14 @@
/*
** LED stuff
*/
-#if defined(RTA)
-#define LED_OFF ((ushort) 0) /* LED off */
-#define LED_RED ((ushort) 1) /* LED Red */
-#define LED_GREEN ((ushort) 2) /* LED Green */
-#define LED_ORANGE ((ushort) 4) /* LED Orange */
-#define LED_1TO8_OPEN ((ushort) 1) /* Port 1->8 LED on */
-#define LED_9TO16_OPEN ((ushort) 2) /* Port 9->16 LED on */
-#define LED_SET_COLOUR(colour) (link->led = (colour))
-#define LED_OR_COLOUR(colour) (link->led |= (colour))
-#define LED_TIMEOUT(time) (link->led_timeout = RioTimePlus(RioTime(),(time)))
-#else
#define LED_SET_COLOUR(colour)
#define LED_OR_COLOUR(colour)
#define LED_TIMEOUT(time)
-#endif /* RTA */
struct LPB {
WORD link_number; /* Link Number */
Channel_ptr in_ch; /* Link In Channel */
Channel_ptr out_ch; /* Link Out Channel */
-#ifdef RTA
- uchar stat_led; /* Port open leds */
- uchar led; /* True, light led! */
-#endif
BYTE attached_serial[4]; /* Attached serial number */
BYTE attached_host_serial[4];
/* Serial number of Host who
@@ -144,30 +128,12 @@ struct LPB {
WORD WaitNoBoot; /* Secs to hold off booting */
PKT_ptr add_packet_list; /* Add packets to here */
PKT_ptr remove_packet_list; /* Send packets from here */
-#ifdef RTA
-#ifdef DCIRRUS
-#define QBUFS_PER_REDIRECT (4 / PKTS_PER_BUFFER + 1)
-#else
-#define QBUFS_PER_REDIRECT (8 / PKTS_PER_BUFFER + 1)
-#endif
- PKT_ptr_ptr rd_add; /* Add a new Packet here */
- Q_BUF_ptr rd_add_qb; /* Pointer to the add Q buf */
- PKT_ptr_ptr rd_add_st_qbb; /* Pointer to start of the Q's buf */
- PKT_ptr_ptr rd_add_end_qbb; /* Pointer to the end of the Q's buf */
- PKT_ptr_ptr rd_remove; /* Remove a Packet here */
- Q_BUF_ptr rd_remove_qb; /* Pointer to the remove Q buf */
- PKT_ptr_ptr rd_remove_st_qbb; /* Pointer to the start of the Q buf */
- PKT_ptr_ptr rd_remove_end_qbb; /* Pointer to the end of the Q buf */
- ushort pkts_in_q; /* Packets in queue */
-#endif
Channel_ptr lrt_fail_chan; /* Lrt's failure channel */
Channel_ptr ltt_fail_chan; /* Ltt's failure channel */
-#if defined (HOST) || defined (INKERNEL)
/* RUP structure for HOST to driver communications */
struct RUP rup;
-#endif
struct RUP link_rup; /* RUP for the link (POLL,
topology etc.) */
WORD attached_link; /* Number of attached link */
diff --git a/drivers/char/rio/list.h b/drivers/char/rio/list.h
index 36aad4c9cb3..79b853140ae 100644
--- a/drivers/char/rio/list.h
+++ b/drivers/char/rio/list.h
@@ -44,8 +44,6 @@ static char *_rio_list_h_sccs = "@(#)list.h 1.9";
#define PKT_IN_USE 0x1
-#ifdef INKERNEL
-
#define ZERO_PTR (ushort) 0x8000
#define CaD PortP->Caddr
@@ -54,143 +52,5 @@ static char *_rio_list_h_sccs = "@(#)list.h 1.9";
** to by the TxAdd pointer has PKT_IN_USE clear in its address.
*/
-#ifndef linux
-#if defined( MIPS ) && !defined( MIPSEISA )
-/* May the shoes of the Devil dance on your grave for creating this */
-#define can_add_transmit(PacketP,PortP) \
- (!((uint)(PacketP = (struct PKT *)RIO_PTR(CaD,RINDW(PortP->TxAdd))) \
- & (PKT_IN_USE<<2)))
-
-#elif defined(MIPSEISA) || defined(nx6000) || \
- defined(drs6000) || defined(UWsparc)
-
-#define can_add_transmit(PacketP,PortP) \
- (!((uint)(PacketP = (struct PKT *)RIO_PTR(CaD,RINDW(PortP->TxAdd))) \
- & PKT_IN_USE))
-
-#else
-#define can_add_transmit(PacketP,PortP) \
- (!((uint)(PacketP = (struct PKT *)RIO_PTR(CaD,*PortP->TxAdd)) \
- & PKT_IN_USE))
-#endif
-
-/*
-** To add a packet to the queue, you set the PKT_IN_USE bit in the address,
-** and then move the TxAdd pointer along one position to point to the next
-** packet pointer. You must wrap the pointer from the end back to the start.
-*/
-#if defined(MIPS) || defined(nx6000) || defined(drs6000) || defined(UWsparc)
-# define add_transmit(PortP) \
- WINDW(PortP->TxAdd,RINDW(PortP->TxAdd) | PKT_IN_USE);\
- if (PortP->TxAdd == PortP->TxEnd)\
- PortP->TxAdd = PortP->TxStart;\
- else\
- PortP->TxAdd++;\
- WWORD(PortP->PhbP->tx_add , RIO_OFF(CaD,PortP->TxAdd));
-#elif defined(AIX)
-# define add_transmit(PortP) \
- {\
- register ushort *TxAddP = (ushort *)RIO_PTR(Cad,PortP->TxAddO);\
- WINDW( TxAddP, RINDW( TxAddP ) | PKT_IN_USE );\
- if (PortP->TxAddO == PortP->TxEndO )\
- PortP->TxAddO = PortP->TxStartO;\
- else\
- PortP->TxAddO += sizeof(ushort);\
- WWORD(((PHB *)RIO_PTR(Cad,PortP->PhbO))->tx_add , PortP->TxAddO );\
- }
-#else
-# define add_transmit(PortP) \
- *PortP->TxAdd |= PKT_IN_USE;\
- if (PortP->TxAdd == PortP->TxEnd)\
- PortP->TxAdd = PortP->TxStart;\
- else\
- PortP->TxAdd++;\
- PortP->PhbP->tx_add = RIO_OFF(CaD,PortP->TxAdd);
-#endif
-
-/*
-** can_remove_receive( PacketP, PortP ) returns non-zero if PKT_IN_USE is set
-** for the next packet on the queue. It will also set PacketP to point to the
-** relevant packet, [having cleared the PKT_IN_USE bit]. If PKT_IN_USE is clear,
-** then can_remove_receive() returns 0.
-*/
-#if defined(MIPS) || defined(nx6000) || defined(drs6000) || defined(UWsparc)
-# define can_remove_receive(PacketP,PortP) \
- ((RINDW(PortP->RxRemove) & PKT_IN_USE) ? \
- (PacketP=(struct PKT *)RIO_PTR(CaD,(RINDW(PortP->RxRemove) & ~PKT_IN_USE))):0)
-#elif defined(AIX)
-# define can_remove_receive(PacketP,PortP) \
- ((RINDW((ushort *)RIO_PTR(Cad,PortP->RxRemoveO)) & PKT_IN_USE) ? \
- (PacketP=(struct PKT *)RIO_PTR(Cad,RINDW((ushort *)RIO_PTR(Cad,PortP->RxRemoveO)) & ~PKT_IN_USE)):0)
-#else
-# define can_remove_receive(PacketP,PortP) \
- ((*PortP->RxRemove & PKT_IN_USE) ? \
- (PacketP=(struct PKT *)RIO_PTR(CaD,(*PortP->RxRemove & ~PKT_IN_USE))):0)
-#endif
-
-
-/*
-** Will God see it within his heart to forgive us for this thing that
-** we have created? To remove a packet from the receive queue you clear
-** its PKT_IN_USE bit, and then bump the pointers. Once the pointers
-** get to the end, they must be wrapped back to the start.
-*/
-#if defined(MIPS) || defined(nx6000) || defined(drs6000) || defined(UWsparc)
-# define remove_receive(PortP) \
- WINDW(PortP->RxRemove, (RINDW(PortP->RxRemove) & ~PKT_IN_USE));\
- if (PortP->RxRemove == PortP->RxEnd)\
- PortP->RxRemove = PortP->RxStart;\
- else\
- PortP->RxRemove++;\
- WWORD(PortP->PhbP->rx_remove , RIO_OFF(CaD,PortP->RxRemove));
-#elif defined(AIX)
-# define remove_receive(PortP) \
- {\
- register ushort *RxRemoveP = (ushort *)RIO_PTR(Cad,PortP->RxRemoveO);\
- WINDW( RxRemoveP, RINDW( RxRemoveP ) & ~PKT_IN_USE );\
- if (PortP->RxRemoveO == PortP->RxEndO)\
- PortP->RxRemoveO = PortP->RxStartO;\
- else\
- PortP->RxRemoveO += sizeof(ushort);\
- WWORD(((PHB *)RIO_PTR(Cad,PortP->PhbO))->rx_remove, PortP->RxRemoveO );\
- }
-#else
-# define remove_receive(PortP) \
- *PortP->RxRemove &= ~PKT_IN_USE;\
- if (PortP->RxRemove == PortP->RxEnd)\
- PortP->RxRemove = PortP->RxStart;\
- else\
- PortP->RxRemove++;\
- PortP->PhbP->rx_remove = RIO_OFF(CaD,PortP->RxRemove);
-#endif
-#endif
-
-
-#else /* !IN_KERNEL */
-
-#define ZERO_PTR NULL
-
-
-#ifdef HOST
-/* #define can_remove_transmit(pkt,phb) ((((char*)pkt = (*(char**)(phb->tx_remove))-1) || 1)) && (*phb->u3.s2.tx_remove_ptr & PKT_IN_USE)) */
-#define remove_transmit(phb) *phb->u3.s2.tx_remove_ptr &= ~(ushort)PKT_IN_USE;\
- if (phb->tx_remove == phb->tx_end)\
- phb->tx_remove = phb->tx_start;\
- else\
- phb->tx_remove++;
-#define can_add_receive(phb) !(*phb->u4.s2.rx_add_ptr & PKT_IN_USE)
-#define add_receive(pkt,phb) *phb->rx_add = pkt;\
- *phb->u4.s2.rx_add_ptr |= PKT_IN_USE;\
- if (phb->rx_add == phb->rx_end)\
- phb->rx_add = phb->rx_start;\
- else\
- phb->rx_add++;
-#endif
-#endif
-
-#ifdef RTA
-#define splx(oldspl) if ((oldspl) == 0) spl0()
-#endif
-
#endif /* ifndef _list.h */
/*********** end of file ***********/
diff --git a/drivers/char/rio/parmmap.h b/drivers/char/rio/parmmap.h
index fe4e0056706..e24acc1d184 100644
--- a/drivers/char/rio/parmmap.h
+++ b/drivers/char/rio/parmmap.h
@@ -78,14 +78,9 @@ struct PARM_MAP {
WORD idle_count; /* Idle time counter */
WORD busy_count; /* Busy counter */
WORD idle_control; /* Control Idle Process */
-#if defined(HOST) || defined(INKERNEL)
WORD tx_intr; /* TX interrupt pending */
WORD rx_intr; /* RX interrupt pending */
WORD rup_intr; /* RUP interrupt pending */
-#endif
-#if defined(RTA)
- WORD dying_count; /* Count of processes dead */
-#endif
};
#endif
diff --git a/drivers/char/rio/phb.h b/drivers/char/rio/phb.h
index 3baebf8513a..2663ca0306e 100644
--- a/drivers/char/rio/phb.h
+++ b/drivers/char/rio/phb.h
@@ -44,17 +44,6 @@
#endif
- /*************************************************
- * Set the LIMIT values.
- ************************************************/
-#ifdef RTA
-#define RX_LIMIT (ushort) 3
-#endif
-#ifdef HOST
-#define RX_LIMIT (ushort) 1
-#endif
-
-
/*************************************************
* Handshake asserted. Deasserted by the LTT(s)
************************************************/
@@ -69,11 +58,7 @@
/*************************************************
* Maximum number of PHB's
************************************************/
-#if defined (HOST) || defined (INKERNEL)
#define MAX_PHB ((ushort) 128) /* range 0-127 */
-#else
-#define MAX_PHB ((ushort) 8) /* range 0-7 */
-#endif
/*************************************************
* Defines for the mode fields
@@ -139,141 +124,23 @@
* the start. The pointer tx_add points to a SPACE to put a Packet.
* The pointer tx_remove points to the next Packet to remove
*************************************************************************/
-#ifndef INKERNEL
-#define src_unit u2.s2.unit
-#define src_port u2.s2.port
-#define dest_unit u1.s1.unit
-#define dest_port u1.s1.port
-#endif
-#ifdef HOST
-#define tx_start u3.s1.tx_start_ptr_ptr
-#define tx_add u3.s1.tx_add_ptr_ptr
-#define tx_end u3.s1.tx_end_ptr_ptr
-#define tx_remove u3.s1.tx_remove_ptr_ptr
-#define rx_start u4.s1.rx_start_ptr_ptr
-#define rx_add u4.s1.rx_add_ptr_ptr
-#define rx_end u4.s1.rx_end_ptr_ptr
-#define rx_remove u4.s1.rx_remove_ptr_ptr
-#endif
typedef struct PHB PHB;
struct PHB {
-#ifdef RTA
- ushort port;
-#endif
-#ifdef INKERNEL
WORD source;
-#else
- union {
- ushort source; /* Complete source */
- struct {
- unsigned char unit; /* Source unit */
- unsigned char port; /* Source port */
- } s2;
- } u2;
-#endif
WORD handshake;
WORD status;
NUMBER timeout; /* Maximum of 1.9 seconds */
WORD link; /* Send down this link */
-#ifdef INKERNEL
WORD destination;
-#else
- union {
- ushort destination; /* Complete destination */
- struct {
- unsigned char unit; /* Destination unit */
- unsigned char port; /* Destination port */
- } s1;
- } u1;
-#endif
-#ifdef RTA
- ushort tx_pkts_added;
- ushort tx_pkts_removed;
- Q_BUF_ptr tx_q_start; /* Start of the Q list chain */
- short num_tx_q_bufs; /* Number of Q buffers in the chain */
- PKT_ptr_ptr tx_add; /* Add a new Packet here */
- Q_BUF_ptr tx_add_qb; /* Pointer to the add Q buf */
- PKT_ptr_ptr tx_add_st_qbb; /* Pointer to start of the Q's buf */
- PKT_ptr_ptr tx_add_end_qbb; /* Pointer to the end of the Q's buf */
- PKT_ptr_ptr tx_remove; /* Remove a Packet here */
- Q_BUF_ptr tx_remove_qb; /* Pointer to the remove Q buf */
- PKT_ptr_ptr tx_remove_st_qbb; /* Pointer to the start of the Q buf */
- PKT_ptr_ptr tx_remove_end_qbb; /* Pointer to the end of the Q buf */
-#endif
-#ifdef INKERNEL
PKT_ptr_ptr tx_start;
PKT_ptr_ptr tx_end;
PKT_ptr_ptr tx_add;
PKT_ptr_ptr tx_remove;
-#endif
-#ifdef HOST
- union {
- struct {
- PKT_ptr_ptr tx_start_ptr_ptr;
- PKT_ptr_ptr tx_end_ptr_ptr;
- PKT_ptr_ptr tx_add_ptr_ptr;
- PKT_ptr_ptr tx_remove_ptr_ptr;
- } s1;
- struct {
- ushort *tx_start_ptr;
- ushort *tx_end_ptr;
- ushort *tx_add_ptr;
- ushort *tx_remove_ptr;
- } s2;
- } u3;
-#endif
-#ifdef RTA
- ushort rx_pkts_added;
- ushort rx_pkts_removed;
- Q_BUF_ptr rx_q_start; /* Start of the Q list chain */
- short num_rx_q_bufs; /* Number of Q buffers in the chain */
- PKT_ptr_ptr rx_add; /* Add a new Packet here */
- Q_BUF_ptr rx_add_qb; /* Pointer to the add Q buf */
- PKT_ptr_ptr rx_add_st_qbb; /* Pointer to start of the Q's buf */
- PKT_ptr_ptr rx_add_end_qbb; /* Pointer to the end of the Q's buf */
- PKT_ptr_ptr rx_remove; /* Remove a Packet here */
- Q_BUF_ptr rx_remove_qb; /* Pointer to the remove Q buf */
- PKT_ptr_ptr rx_remove_st_qbb; /* Pointer to the start of the Q buf */
- PKT_ptr_ptr rx_remove_end_qbb; /* Pointer to the end of the Q buf */
-#endif
-#ifdef INKERNEL
PKT_ptr_ptr rx_start;
PKT_ptr_ptr rx_end;
PKT_ptr_ptr rx_add;
PKT_ptr_ptr rx_remove;
-#endif
-#ifdef HOST
- union {
- struct {
- PKT_ptr_ptr rx_start_ptr_ptr;
- PKT_ptr_ptr rx_end_ptr_ptr;
- PKT_ptr_ptr rx_add_ptr_ptr;
- PKT_ptr_ptr rx_remove_ptr_ptr;
- } s1;
- struct {
- ushort *rx_start_ptr;
- ushort *rx_end_ptr;
- ushort *rx_add_ptr;
- ushort *rx_remove_ptr;
- } s2;
- } u4;
-#endif
-
-#ifdef RTA /* some fields for the remotes */
- ushort flush_count; /* Count of write flushes */
- ushort txmode; /* Modes for tx */
- ushort rxmode; /* Modes for rx */
- ushort portmode; /* Generic modes */
- ushort column; /* TAB3 column count */
- ushort tx_subscript; /* (TX) Subscript into data field */
- ushort rx_subscript; /* (RX) Subscript into data field */
- PKT_ptr rx_incomplete; /* Hold an incomplete packet here */
- ushort modem_bits; /* Modem bits to mask */
- ushort lastModem; /* Modem control lines. */
- ushort addr; /* Address for sub commands */
- ushort MonitorTstate; /* TRUE if monitoring tstop */
-#endif
};
diff --git a/drivers/char/rio/pkt.h b/drivers/char/rio/pkt.h
index 882fd429ac2..7011e52e82d 100644
--- a/drivers/char/rio/pkt.h
+++ b/drivers/char/rio/pkt.h
@@ -70,39 +70,12 @@
#define CONTROL_DATA_WNDW (DATA_WNDW << 8)
struct PKT {
-#ifdef INKERNEL
BYTE dest_unit; /* Destination Unit Id */
BYTE dest_port; /* Destination POrt */
BYTE src_unit; /* Source Unit Id */
BYTE src_port; /* Source POrt */
-#else
- union {
- ushort destination; /* Complete destination */
- struct {
- unsigned char unit; /* Destination unit */
- unsigned char port; /* Destination port */
- } s1;
- } u1;
- union {
- ushort source; /* Complete source */
- struct {
- unsigned char unit; /* Source unit */
- unsigned char port; /* Source port */
- } s2;
- } u2;
-#endif
-#ifdef INKERNEL
BYTE len;
BYTE control;
-#else
- union {
- ushort control;
- struct {
- unsigned char len;
- unsigned char control;
- } s3;
- } u3;
-#endif
BYTE data[PKT_MAX_DATA_LEN];
/* Actual data :-) */
WORD csum; /* C-SUM */
diff --git a/drivers/char/rio/qbuf.h b/drivers/char/rio/qbuf.h
index acd9e8e5307..391ffc33553 100644
--- a/drivers/char/rio/qbuf.h
+++ b/drivers/char/rio/qbuf.h
@@ -46,11 +46,7 @@ static char *_rio_qbuf_h_sccs = "@(#)qbuf.h 1.1";
-#ifdef HOST
-#define PKTS_PER_BUFFER 1
-#else
#define PKTS_PER_BUFFER (220 / PKT_LENGTH)
-#endif
typedef struct Q_BUF Q_BUF;
struct Q_BUF {
diff --git a/drivers/char/rio/riotypes.h b/drivers/char/rio/riotypes.h
index 9b67e2468be..46084d5c7e9 100644
--- a/drivers/char/rio/riotypes.h
+++ b/drivers/char/rio/riotypes.h
@@ -43,9 +43,6 @@
#endif
#endif
-#ifdef INKERNEL
-
-#if !defined(MIPSAT)
typedef unsigned short NUMBER_ptr;
typedef unsigned short WORD_ptr;
typedef unsigned short BYTE_ptr;
@@ -65,69 +62,6 @@ typedef unsigned short RUP_ptr;
typedef unsigned short short_ptr;
typedef unsigned short u_short_ptr;
typedef unsigned short ushort_ptr;
-#else
-/* MIPSAT types */
-typedef char RIO_POINTER[8];
-typedef RIO_POINTER NUMBER_ptr;
-typedef RIO_POINTER WORD_ptr;
-typedef RIO_POINTER BYTE_ptr;
-typedef RIO_POINTER char_ptr;
-typedef RIO_POINTER Channel_ptr;
-typedef RIO_POINTER FREE_LIST_ptr_ptr;
-typedef RIO_POINTER FREE_LIST_ptr;
-typedef RIO_POINTER LPB_ptr;
-typedef RIO_POINTER Process_ptr;
-typedef RIO_POINTER PHB_ptr;
-typedef RIO_POINTER PKT_ptr;
-typedef RIO_POINTER PKT_ptr_ptr;
-typedef RIO_POINTER Q_BUF_ptr;
-typedef RIO_POINTER Q_BUF_ptr_ptr;
-typedef RIO_POINTER ROUTE_STR_ptr;
-typedef RIO_POINTER RUP_ptr;
-typedef RIO_POINTER short_ptr;
-typedef RIO_POINTER u_short_ptr;
-typedef RIO_POINTER ushort_ptr;
-#endif
-
-#else /* not INKERNEL */
-typedef unsigned char BYTE;
-typedef unsigned short WORD;
-typedef unsigned long DWORD;
-typedef short NUMBER;
-typedef short *NUMBER_ptr;
-typedef unsigned short *WORD_ptr;
-typedef unsigned char *BYTE_ptr;
-typedef unsigned char uchar;
-typedef unsigned short ushort;
-typedef unsigned int uint;
-typedef unsigned long ulong;
-typedef unsigned char u_char;
-typedef unsigned short u_short;
-typedef unsigned int u_int;
-typedef unsigned long u_long;
-typedef unsigned short ERROR;
-typedef unsigned long ID;
-typedef char *char_ptr;
-typedef Channel *Channel_ptr;
-typedef struct FREE_LIST *FREE_LIST_ptr;
-typedef struct FREE_LIST **FREE_LIST_ptr_ptr;
-typedef struct LPB *LPB_ptr;
-typedef struct Process *Process_ptr;
-typedef struct PHB *PHB_ptr;
-typedef struct PKT *PKT_ptr;
-typedef struct PKT **PKT_ptr_ptr;
-typedef struct Q_BUF *Q_BUF_ptr;
-typedef struct Q_BUF **Q_BUF_ptr_ptr;
-typedef struct ROUTE_STR *ROUTE_STR_ptr;
-typedef struct RUP *RUP_ptr;
-typedef short *short_ptr;
-typedef u_short *u_short_ptr;
-typedef ushort *ushort_ptr;
-typedef struct PKT PKT;
-typedef struct LPB LPB;
-typedef struct RUP RUP;
-#endif
-
#endif /* __riotypes__ */
diff --git a/drivers/char/rio/rup.h b/drivers/char/rio/rup.h
index 8d44fec91dd..f74f67c6f70 100644
--- a/drivers/char/rio/rup.h
+++ b/drivers/char/rio/rup.h
@@ -43,12 +43,7 @@
#endif
#endif
-#if defined( HOST ) || defined( INKERNEL )
#define MAX_RUP ((short) 16)
-#endif
-#ifdef RTA
-#define MAX_RUP ((short) 1)
-#endif
#define PKTS_PER_RUP ((short) 2) /* They are always used in pairs */
diff --git a/drivers/char/rio/sam.h b/drivers/char/rio/sam.h
index 31494054b21..6f754e19015 100644
--- a/drivers/char/rio/sam.h
+++ b/drivers/char/rio/sam.h
@@ -43,10 +43,6 @@
#endif
-#if !defined( HOST ) && !defined( INKERNEL )
-#define RTA 1
-#endif
-
#define NUM_FREE_LIST_UNITS 500
#ifndef FALSE
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 0949dcef069..7edc6a4dbdc 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -433,7 +433,7 @@ static void rp_do_receive(struct r_port *info,
count += ToRecv;
}
/* Push the data up to the tty layer */
- ld->receive_buf(tty, cbuf, fbuf, count);
+ ld->receive_buf(tty, chead, fhead, count);
done:
tty_ldisc_deref(ld);
}
diff --git a/drivers/char/sx.c b/drivers/char/sx.c
index 64bf89cb574..c2490e270f1 100644
--- a/drivers/char/sx.c
+++ b/drivers/char/sx.c
@@ -931,7 +931,7 @@ static int sx_set_real_termios (void *ptr)
case CS6:sx_write_channel_byte (port, hi_mask, 0x3f);break;
case CS5:sx_write_channel_byte (port, hi_mask, 0x1f);break;
default:
- printk (KERN_INFO "sx: Invalid wordsize: %d\n", CFLAG & CSIZE);
+ printk (KERN_INFO "sx: Invalid wordsize: %u\n", CFLAG & CSIZE);
break;
}
@@ -958,7 +958,7 @@ static int sx_set_real_termios (void *ptr)
} else {
set_bit(TTY_HW_COOK_IN, &port->gs.tty->flags);
}
- sx_dprintk (SX_DEBUG_TERMIOS, "iflags: %x(%d) ",
+ sx_dprintk (SX_DEBUG_TERMIOS, "iflags: %x(%d) ",
port->gs.tty->termios->c_iflag,
I_OTHER(port->gs.tty));
@@ -973,7 +973,7 @@ static int sx_set_real_termios (void *ptr)
} else {
clear_bit(TTY_HW_COOK_OUT, &port->gs.tty->flags);
}
- sx_dprintk (SX_DEBUG_TERMIOS, "oflags: %x(%d)\n",
+ sx_dprintk (SX_DEBUG_TERMIOS, "oflags: %x(%d)\n",
port->gs.tty->termios->c_oflag,
O_OTHER(port->gs.tty));
/* port->c_dcd = sx_get_CD (port); */
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index eb8b5be4e24..076e07c1da3 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -253,6 +253,7 @@ static void tty_buffer_free_all(struct tty_struct *tty)
static void tty_buffer_init(struct tty_struct *tty)
{
+ spin_lock_init(&tty->buf.lock);
tty->buf.head = NULL;
tty->buf.tail = NULL;
tty->buf.free = NULL;
@@ -266,6 +267,7 @@ static struct tty_buffer *tty_buffer_alloc(size_t size)
p->used = 0;
p->size = size;
p->next = NULL;
+ p->active = 0;
p->char_buf_ptr = (char *)(p->data);
p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
/* printk("Flip create %p\n", p); */
@@ -312,25 +314,36 @@ static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
int tty_buffer_request_room(struct tty_struct *tty, size_t size)
{
- struct tty_buffer *b = tty->buf.tail, *n;
- int left = 0;
+ struct tty_buffer *b, *n;
+ int left;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tty->buf.lock, flags);
/* OPTIMISATION: We could keep a per tty "zero" sized buffer to
remove this conditional if its worth it. This would be invisible
to the callers */
- if(b != NULL)
+ if ((b = tty->buf.tail) != NULL) {
left = b->size - b->used;
- if(left >= size)
- return size;
- /* This is the slow path - looking for new buffers to use */
- n = tty_buffer_find(tty, size);
- if(n == NULL)
- return left;
- if(b != NULL)
- b->next = n;
- else
- tty->buf.head = n;
- tty->buf.tail = n;
+ b->active = 1;
+ } else
+ left = 0;
+
+ if (left < size) {
+ /* This is the slow path - looking for new buffers to use */
+ if ((n = tty_buffer_find(tty, size)) != NULL) {
+ if (b != NULL) {
+ b->next = n;
+ b->active = 0;
+ } else
+ tty->buf.head = n;
+ tty->buf.tail = n;
+ n->active = 1;
+ } else
+ size = left;
+ }
+
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
return size;
}
@@ -396,10 +409,12 @@ EXPORT_SYMBOL_GPL(tty_insert_flip_string_flags);
int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size)
{
int space = tty_buffer_request_room(tty, size);
- struct tty_buffer *tb = tty->buf.tail;
- *chars = tb->char_buf_ptr + tb->used;
- memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
- tb->used += space;
+ if (likely(space)) {
+ struct tty_buffer *tb = tty->buf.tail;
+ *chars = tb->char_buf_ptr + tb->used;
+ memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
+ tb->used += space;
+ }
return space;
}
@@ -416,10 +431,12 @@ EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size)
{
int space = tty_buffer_request_room(tty, size);
- struct tty_buffer *tb = tty->buf.tail;
- *chars = tb->char_buf_ptr + tb->used;
- *flags = tb->flag_buf_ptr + tb->used;
- tb->used += space;
+ if (likely(space)) {
+ struct tty_buffer *tb = tty->buf.tail;
+ *chars = tb->char_buf_ptr + tb->used;
+ *flags = tb->flag_buf_ptr + tb->used;
+ tb->used += space;
+ }
return space;
}
@@ -2747,20 +2764,20 @@ static void flush_to_ldisc(void *private_)
schedule_delayed_work(&tty->buf.work, 1);
goto out;
}
- spin_lock_irqsave(&tty->read_lock, flags);
- while((tbuf = tty->buf.head) != NULL) {
+ spin_lock_irqsave(&tty->buf.lock, flags);
+ while((tbuf = tty->buf.head) != NULL && !tbuf->active) {
tty->buf.head = tbuf->next;
if (tty->buf.head == NULL)
tty->buf.tail = NULL;
- spin_unlock_irqrestore(&tty->read_lock, flags);
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
/* printk("Process buffer %p for %d\n", tbuf, tbuf->used); */
disc->receive_buf(tty, tbuf->char_buf_ptr,
tbuf->flag_buf_ptr,
tbuf->used);
- spin_lock_irqsave(&tty->read_lock, flags);
+ spin_lock_irqsave(&tty->buf.lock, flags);
tty_buffer_free(tty, tbuf);
}
- spin_unlock_irqrestore(&tty->read_lock, flags);
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
out:
tty_ldisc_deref(disc);
}
@@ -2852,6 +2869,12 @@ EXPORT_SYMBOL(tty_get_baud_rate);
void tty_flip_buffer_push(struct tty_struct *tty)
{
+ unsigned long flags;
+ spin_lock_irqsave(&tty->buf.lock, flags);
+ if (tty->buf.tail != NULL)
+ tty->buf.tail->active = 0;
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
+
if (tty->low_latency)
flush_to_ldisc((void *) tty);
else
diff --git a/drivers/char/watchdog/sbc_epx_c3.c b/drivers/char/watchdog/sbc_epx_c3.c
index 951764614eb..7a4dfb95d08 100644
--- a/drivers/char/watchdog/sbc_epx_c3.c
+++ b/drivers/char/watchdog/sbc_epx_c3.c
@@ -25,6 +25,7 @@
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/init.h>
+#include <linux/ioport.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -181,11 +182,14 @@ static int __init watchdog_init(void)
{
int ret;
+ if (!request_region(EPXC3_WATCHDOG_CTL_REG, 2, "epxc3_watchdog"))
+ return -EBUSY;
+
ret = register_reboot_notifier(&epx_c3_notifier);
if (ret) {
printk(KERN_ERR PFX "cannot register reboot notifier "
"(err=%d)\n", ret);
- return ret;
+ goto out;
}
ret = misc_register(&epx_c3_miscdev);
@@ -193,18 +197,23 @@ static int __init watchdog_init(void)
printk(KERN_ERR PFX "cannot register miscdev on minor=%d "
"(err=%d)\n", WATCHDOG_MINOR, ret);
unregister_reboot_notifier(&epx_c3_notifier);
- return ret;
+ goto out;
}
printk(banner);
return 0;
+
+out:
+ release_region(EPXC3_WATCHDOG_CTL_REG, 2);
+ return ret;
}
static void __exit watchdog_exit(void)
{
misc_deregister(&epx_c3_miscdev);
unregister_reboot_notifier(&epx_c3_notifier);
+ release_region(EPXC3_WATCHDOG_CTL_REG, 2);
}
module_init(watchdog_init);
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 4819e7fc00d..18a45565112 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -11,7 +11,6 @@ menu 'EDAC - error detection and reporting (RAS)'
config EDAC
tristate "EDAC core system error reporting"
depends on X86
- default y
help
EDAC is designed to report errors in the core system.
These are low-level errors that are reported in the CPU or
@@ -46,7 +45,7 @@ config EDAC_MM_EDAC
config EDAC_AMD76X
tristate "AMD 76x (760, 762, 768)"
- depends on EDAC_MM_EDAC && PCI
+ depends on EDAC_MM_EDAC && PCI && X86_32
help
Support for error detection and correction on the AMD 76x
series of chipsets used with the Athlon processor.
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c
index 770a5a63307..c454ded2b06 100644
--- a/drivers/edac/e752x_edac.c
+++ b/drivers/edac/e752x_edac.c
@@ -1039,10 +1039,10 @@ MODULE_DEVICE_TABLE(pci, e752x_pci_tbl);
static struct pci_driver e752x_driver = {
- name: BS_MOD_STR,
- probe: e752x_init_one,
- remove: __devexit_p(e752x_remove_one),
- id_table: e752x_pci_tbl,
+ .name = BS_MOD_STR,
+ .probe = e752x_init_one,
+ .remove = __devexit_p(e752x_remove_one),
+ .id_table = e752x_pci_tbl,
};
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 4be9bd0a126..b10ee4698b1 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -14,7 +14,6 @@
#include <linux/config.h>
-#include <linux/version.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/kernel.h>
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index 1c81174595b..d633081fa4c 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -52,9 +52,9 @@ config IDE
if IDE
-config IDE_MAX_HWIFS
+config IDE_MAX_HWIFS
int "Max IDE interfaces"
- depends on ALPHA || SUPERH
+ depends on ALPHA || SUPERH || IA64
default 4
help
This is the maximum number of IDE hardware interfaces that will
@@ -162,8 +162,8 @@ config BLK_DEV_IDECS
tristate "PCMCIA IDE support"
depends on PCMCIA
help
- Support for outboard IDE disks, tape drives, and CD-ROM drives
- connected through a PCMCIA card.
+ Support for Compact Flash cards, outboard IDE disks, tape drives,
+ and CD-ROM drives connected through a PCMCIA card.
config BLK_DEV_IDECD
tristate "Include IDE/ATAPI CDROM support"
@@ -267,7 +267,7 @@ config IDE_TASK_IOCTL
help
This is a direct raw access to the media. It is a complex but
elegant solution to test and validate the domain of the hardware and
- perform below the driver data recover if needed. This is the most
+ perform below the driver data recovery if needed. This is the most
basic form of media-forensics.
If you are unsure, say N here.
@@ -525,7 +525,7 @@ config BLK_DEV_CS5520
tristate "Cyrix CS5510/20 MediaGX chipset support (VERY EXPERIMENTAL)"
depends on EXPERIMENTAL
help
- Include support for PIO tuning an virtual DMA on the Cyrix MediaGX
+ Include support for PIO tuning and virtual DMA on the Cyrix MediaGX
5510/5520 chipset. This will automatically be detected and
configured if found.
@@ -662,7 +662,7 @@ config PDC202XX_BURST
It was originally designed for the PDC20246/Ultra33, whose BIOS will
only setup UDMA on the first two PDC20246 cards. It has also been
- used succesfully on a PDC20265/Ultra100, allowing use of UDMA modes
+ used successfully on a PDC20265/Ultra100, allowing use of UDMA modes
when the PDC20265 BIOS has been disabled (for faster boot up).
Please read the comments at the top of
@@ -673,13 +673,6 @@ config PDC202XX_BURST
config BLK_DEV_PDC202XX_NEW
tristate "PROMISE PDC202{68|69|70|71|75|76|77} support"
-# FIXME - probably wants to be one for old and for new
-config PDC202XX_FORCE
- bool "Enable controller even if disabled by BIOS"
- depends on BLK_DEV_PDC202XX_NEW
- help
- Enable the PDC202xx controller even if it has been disabled in the BIOS setup.
-
config BLK_DEV_SVWKS
tristate "ServerWorks OSB4/CSB5/CSB6 chipsets support"
help
@@ -722,7 +715,7 @@ config BLK_DEV_SIS5513
config BLK_DEV_SLC90E66
tristate "SLC90E66 chipset support"
help
- This driver ensures (U)DMA support for Victroy66 SouthBridges for
+ This driver ensures (U)DMA support for Victory66 SouthBridges for
SMsC with Intel NorthBridges. This is an Ultra66 based chipset.
The nice thing about it is that you can mix Ultra/DMA/PIO devices
and it will handle timing cycles. Since this is an improved
@@ -1060,7 +1053,7 @@ config IDEDMA_IVB
in that mode with an 80c ribbon.
If you are experiencing compatibility or performance problems, you
- MAY try to answering Y here. However, it does not necessarily solve
+ MAY try to answer Y here. However, it does not necessarily solve
any of your problems, it could even cause more of them.
It is normally safe to answer Y; however, the default is N.
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index ca25f9e3d0f..6c60a9d2afd 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -776,7 +776,7 @@ static void update_ordered(ide_drive_t *drive)
ide_id_has_flush_cache_ext(id));
printk(KERN_INFO "%s: cache flushes %ssupported\n",
- drive->name, barrier ? "" : "not");
+ drive->name, barrier ? "" : "not ");
if (barrier) {
ordered = QUEUE_ORDERED_DRAIN_FLUSH;
@@ -889,11 +889,7 @@ static void idedisk_setup (ide_drive_t *drive)
if (drive->id_read == 0)
return;
- /*
- * CompactFlash cards and their brethern look just like hard drives
- * to us, but they are removable and don't have a doorlock mechanism.
- */
- if (drive->removable && !(drive->is_flash)) {
+ if (drive->removable) {
/*
* Removable disks (eg. SYQUEST); ignore 'WD' drives
*/
diff --git a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
index 8d50df4526a..c01615dec20 100644
--- a/drivers/ide/ide-io.c
+++ b/drivers/ide/ide-io.c
@@ -55,8 +55,8 @@
#include <asm/io.h>
#include <asm/bitops.h>
-int __ide_end_request(ide_drive_t *drive, struct request *rq, int uptodate,
- int nr_sectors)
+static int __ide_end_request(ide_drive_t *drive, struct request *rq,
+ int uptodate, int nr_sectors)
{
int ret = 1;
@@ -91,7 +91,6 @@ int __ide_end_request(ide_drive_t *drive, struct request *rq, int uptodate,
return ret;
}
-EXPORT_SYMBOL(__ide_end_request);
/**
* ide_end_request - complete an IDE I/O
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index af7af958ab3..b72dde70840 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -1243,6 +1243,7 @@ int ide_wait_not_busy(ide_hwif_t *hwif, unsigned long timeout)
*/
if (stat == 0xff)
return -ENODEV;
+ touch_softlockup_watchdog();
}
return -EBUSY;
}
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index e7425546b4b..427d1c20417 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -125,45 +125,6 @@ static void ide_disk_init_mult_count(ide_drive_t *drive)
}
/**
- * drive_is_flashcard - check for compact flash
- * @drive: drive to check
- *
- * CompactFlash cards and their brethern pretend to be removable
- * hard disks, except:
- * (1) they never have a slave unit, and
- * (2) they don't have doorlock mechanisms.
- * This test catches them, and is invoked elsewhere when setting
- * appropriate config bits.
- *
- * FIXME: This treatment is probably applicable for *all* PCMCIA (PC CARD)
- * devices, so in linux 2.3.x we should change this to just treat all
- * PCMCIA drives this way, and get rid of the model-name tests below
- * (too big of an interface change for 2.4.x).
- * At that time, we might also consider parameterizing the timeouts and
- * retries, since these are MUCH faster than mechanical drives. -M.Lord
- */
-
-static inline int drive_is_flashcard (ide_drive_t *drive)
-{
- struct hd_driveid *id = drive->id;
-
- if (drive->removable) {
- if (id->config == 0x848a) return 1; /* CompactFlash */
- if (!strncmp(id->model, "KODAK ATA_FLASH", 15) /* Kodak */
- || !strncmp(id->model, "Hitachi CV", 10) /* Hitachi */
- || !strncmp(id->model, "SunDisk SDCFB", 13) /* old SanDisk */
- || !strncmp(id->model, "SanDisk SDCFB", 13) /* SanDisk */
- || !strncmp(id->model, "HAGIWARA HPC", 12) /* Hagiwara */
- || !strncmp(id->model, "LEXAR ATA_FLASH", 15) /* Lexar */
- || !strncmp(id->model, "ATA_FLASH", 9)) /* Simple Tech */
- {
- return 1; /* yes, it is a flash memory card */
- }
- }
- return 0; /* no, it is not a flash memory card */
-}
-
-/**
* do_identify - identify a drive
* @drive: drive to identify
* @cmd: command used
@@ -278,13 +239,17 @@ static inline void do_identify (ide_drive_t *drive, u8 cmd)
/*
* Not an ATAPI device: looks like a "regular" hard disk
*/
- if (id->config & (1<<7))
+
+ /*
+ * 0x848a = CompactFlash device
+ * These are *not* removable in Linux definition of the term
+ */
+
+ if ((id->config != 0x848a) && (id->config & (1<<7)))
drive->removable = 1;
- if (drive_is_flashcard(drive))
- drive->is_flash = 1;
drive->media = ide_disk;
- printk("%s DISK drive\n", (drive->is_flash) ? "CFA" : "ATA" );
+ printk("%s DISK drive\n", (id->config == 0x848a) ? "CFA" : "ATA" );
QUIRK_LIST(drive);
return;
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index afeb02bbb72..b2cc43702f6 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -242,7 +242,6 @@ static void init_hwif_data(ide_hwif_t *hwif, unsigned int index)
drive->name[2] = 'a' + (index * MAX_DRIVES) + unit;
drive->max_failures = IDE_DEFAULT_MAX_FAILURES;
drive->using_dma = 0;
- drive->is_flash = 0;
drive->vdma = 0;
INIT_LIST_HEAD(&drive->list);
init_completion(&drive->gendev_rel_comp);
diff --git a/drivers/ide/pci/aec62xx.c b/drivers/ide/pci/aec62xx.c
index a21b1e11eef..c743e68c33a 100644
--- a/drivers/ide/pci/aec62xx.c
+++ b/drivers/ide/pci/aec62xx.c
@@ -262,6 +262,21 @@ static unsigned int __devinit init_chipset_aec62xx(struct pci_dev *dev, const ch
else
pci_set_drvdata(dev, (void *) aec6xxx_34_base);
+ /* These are necessary to get AEC6280 Macintosh cards to work */
+ if ((dev->device == PCI_DEVICE_ID_ARTOP_ATP865) ||
+ (dev->device == PCI_DEVICE_ID_ARTOP_ATP865R)) {
+ u8 reg49h = 0, reg4ah = 0;
+ /* Clear reset and test bits. */
+ pci_read_config_byte(dev, 0x49, &reg49h);
+ pci_write_config_byte(dev, 0x49, reg49h & ~0x30);
+ /* Enable chip interrupt output. */
+ pci_read_config_byte(dev, 0x4a, &reg4ah);
+ pci_write_config_byte(dev, 0x4a, reg4ah & ~0x01);
+ /* Enable burst mode. */
+ pci_read_config_byte(dev, 0x4a, &reg4ah);
+ pci_write_config_byte(dev, 0x4a, reg4ah | 0x80);
+ }
+
return dev->irq;
}
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
index 7b589d948bf..940bdd4c578 100644
--- a/drivers/ide/pci/hpt366.c
+++ b/drivers/ide/pci/hpt366.c
@@ -1288,6 +1288,10 @@ static void __devinit hpt37x_clocking(ide_hwif_t *hwif)
goto init_hpt37X_done;
}
}
+ if (!pci_get_drvdata(dev)) {
+ printk("No Clock Stabilization!!!\n");
+ return;
+ }
pll_recal:
if (adjust & 1)
pll -= (adjust >> 1);
diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c
index 108fda83fea..38f41b377ff 100644
--- a/drivers/ide/pci/it821x.c
+++ b/drivers/ide/pci/it821x.c
@@ -733,7 +733,7 @@ static void __devinit it8212_disable_raid(struct pci_dev *dev)
pci_write_config_dword(dev,0x4C, 0x02040204);
pci_write_config_byte(dev, 0x42, 0x36);
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0);
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x20);
}
static unsigned int __devinit init_chipset_it821x(struct pci_dev *dev, const char *name)
diff --git a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c
index fe06ebb0e5b..acd63173199 100644
--- a/drivers/ide/pci/pdc202xx_new.c
+++ b/drivers/ide/pci/pdc202xx_new.c
@@ -420,9 +420,6 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
.init_hwif = init_hwif_pdc202new,
.channels = 2,
.autodma = AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
- .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
.bootable = OFF_BOARD,
},{ /* 3 */
.name = "PDC20271",
@@ -447,9 +444,6 @@ static ide_pci_device_t pdcnew_chipsets[] __devinitdata = {
.init_hwif = init_hwif_pdc202new,
.channels = 2,
.autodma = AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
- .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
.bootable = OFF_BOARD,
},{ /* 6 */
.name = "PDC20277",
diff --git a/drivers/ide/pci/pdc202xx_old.c b/drivers/ide/pci/pdc202xx_old.c
index ad9d95817f9..6f8f8645b02 100644
--- a/drivers/ide/pci/pdc202xx_old.c
+++ b/drivers/ide/pci/pdc202xx_old.c
@@ -786,9 +786,6 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
.init_dma = init_dma_pdc202xx,
.channels = 2,
.autodma = AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
- .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
.bootable = OFF_BOARD,
.extra = 16,
},{ /* 1 */
@@ -799,9 +796,6 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
.init_dma = init_dma_pdc202xx,
.channels = 2,
.autodma = AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
- .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
.bootable = OFF_BOARD,
.extra = 48,
.flags = IDEPCI_FLAG_FORCE_PDC,
@@ -813,9 +807,6 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
.init_dma = init_dma_pdc202xx,
.channels = 2,
.autodma = AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
- .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
.bootable = OFF_BOARD,
.extra = 48,
},{ /* 3 */
@@ -826,9 +817,6 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
.init_dma = init_dma_pdc202xx,
.channels = 2,
.autodma = AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
- .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
.bootable = OFF_BOARD,
.extra = 48,
.flags = IDEPCI_FLAG_FORCE_PDC,
@@ -840,9 +828,6 @@ static ide_pci_device_t pdc202xx_chipsets[] __devinitdata = {
.init_dma = init_dma_pdc202xx,
.channels = 2,
.autodma = AUTODMA,
-#ifndef CONFIG_PDC202XX_FORCE
- .enablebits = {{0x50,0x02,0x02}, {0x50,0x04,0x04}},
-#endif
.bootable = OFF_BOARD,
.extra = 48,
}
diff --git a/drivers/ide/pci/piix.c b/drivers/ide/pci/piix.c
index b3e77df63ce..e9b83e1a302 100644
--- a/drivers/ide/pci/piix.c
+++ b/drivers/ide/pci/piix.c
@@ -135,6 +135,7 @@ static u8 piix_ratemask (ide_drive_t *drive)
case PCI_DEVICE_ID_INTEL_ICH6_19:
case PCI_DEVICE_ID_INTEL_ICH7_21:
case PCI_DEVICE_ID_INTEL_ESB2_18:
+ case PCI_DEVICE_ID_INTEL_ICH8_6:
mode = 3;
break;
/* UDMA 66 capable */
@@ -449,6 +450,7 @@ static unsigned int __devinit init_chipset_piix (struct pci_dev *dev, const char
case PCI_DEVICE_ID_INTEL_ICH6_19:
case PCI_DEVICE_ID_INTEL_ICH7_21:
case PCI_DEVICE_ID_INTEL_ESB2_18:
+ case PCI_DEVICE_ID_INTEL_ICH8_6:
{
unsigned int extra = 0;
pci_read_config_dword(dev, 0x54, &extra);
@@ -575,6 +577,7 @@ static ide_pci_device_t piix_pci_info[] __devinitdata = {
/* 21 */ DECLARE_PIIX_DEV("ICH7"),
/* 22 */ DECLARE_PIIX_DEV("ICH4"),
/* 23 */ DECLARE_PIIX_DEV("ESB2"),
+ /* 24 */ DECLARE_PIIX_DEV("ICH8M"),
};
/**
@@ -651,6 +654,7 @@ static struct pci_device_id piix_pci_tbl[] = {
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_21, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 21},
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 22},
{ PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_18, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 23},
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 24},
{ 0, },
};
MODULE_DEVICE_TABLE(pci, piix_pci_tbl);
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index 1b85ce166af..11fe537e2f6 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -216,7 +216,7 @@ struct Layer1 {
#define GROUP_TEI 127
#define TEI_SAPI 63
#define CTRL_SAPI 0
-#define PACKET_NOACK 250
+#define PACKET_NOACK 7
/* Layer2 Flags */
diff --git a/drivers/isdn/sc/ioctl.c b/drivers/isdn/sc/ioctl.c
index 3314a5a1985..94c9afb7017 100644
--- a/drivers/isdn/sc/ioctl.c
+++ b/drivers/isdn/sc/ioctl.c
@@ -71,14 +71,14 @@ int sc_ioctl(int card, scs_ioctl *data)
/*
* Get the SRec from user space
*/
- if (copy_from_user(srec, data->dataptr, sizeof(srec))) {
+ if (copy_from_user(srec, data->dataptr, SCIOC_SRECSIZE)) {
kfree(rcvmsg);
kfree(srec);
return -EFAULT;
}
status = send_and_receive(card, CMPID, cmReqType2, cmReqClass0, cmReqLoadProc,
- 0, sizeof(srec), srec, rcvmsg, SAR_TIMEOUT);
+ 0, SCIOC_SRECSIZE, srec, rcvmsg, SAR_TIMEOUT);
kfree(rcvmsg);
kfree(srec);
diff --git a/drivers/md/dm-log.c b/drivers/md/dm-log.c
index 74039db846b..d73779a4241 100644
--- a/drivers/md/dm-log.c
+++ b/drivers/md/dm-log.c
@@ -545,7 +545,8 @@ static int core_get_resync_work(struct dirty_log *log, region_t *region)
return 0;
do {
- *region = find_next_zero_bit((unsigned long *) lc->sync_bits,
+ *region = ext2_find_next_zero_bit(
+ (unsigned long *) lc->sync_bits,
lc->region_count,
lc->sync_search);
lc->sync_search = *region + 1;
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 7145cd150f7..d05e3125d29 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1024,7 +1024,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
rdev-> sb_size = (rdev->sb_size | bmask)+1;
if (refdev == 0)
- return 1;
+ ret = 1;
else {
__u64 ev1, ev2;
struct mdp_superblock_1 *refsb =
@@ -1044,7 +1044,9 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
ev2 = le64_to_cpu(refsb->events);
if (ev1 > ev2)
- return 1;
+ ret = 1;
+ else
+ ret = 0;
}
if (minor_version)
rdev->size = ((rdev->bdev->bd_inode->i_size>>9) - le64_to_cpu(sb->data_offset)) / 2;
@@ -1058,7 +1060,7 @@ static int super_1_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version)
if (le32_to_cpu(sb->size) > rdev->size*2)
return -EINVAL;
- return 0;
+ return ret;
}
static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
@@ -1081,7 +1083,7 @@ static int super_1_validate(mddev_t *mddev, mdk_rdev_t *rdev)
mddev->size = le64_to_cpu(sb->size)/2;
mddev->events = le64_to_cpu(sb->events);
mddev->bitmap_offset = 0;
- mddev->default_bitmap_offset = 1024;
+ mddev->default_bitmap_offset = 1024 >> 9;
mddev->recovery_cp = le64_to_cpu(sb->resync_offset);
memcpy(mddev->uuid, sb->set_uuid, 16);
@@ -1161,6 +1163,9 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev)
sb->cnt_corrected_read = atomic_read(&rdev->corrected_errors);
+ sb->raid_disks = cpu_to_le32(mddev->raid_disks);
+ sb->size = cpu_to_le64(mddev->size<<1);
+
if (mddev->bitmap && mddev->bitmap_file == NULL) {
sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_offset);
sb->feature_map = cpu_to_le32(MD_FEATURE_BITMAP_OFFSET);
@@ -2686,14 +2691,6 @@ static int do_md_stop(mddev_t * mddev, int ro)
set_disk_ro(disk, 1);
}
- bitmap_destroy(mddev);
- if (mddev->bitmap_file) {
- atomic_set(&mddev->bitmap_file->f_dentry->d_inode->i_writecount, 1);
- fput(mddev->bitmap_file);
- mddev->bitmap_file = NULL;
- }
- mddev->bitmap_offset = 0;
-
/*
* Free resources if final stop
*/
@@ -2703,6 +2700,14 @@ static int do_md_stop(mddev_t * mddev, int ro)
struct gendisk *disk;
printk(KERN_INFO "md: %s stopped.\n", mdname(mddev));
+ bitmap_destroy(mddev);
+ if (mddev->bitmap_file) {
+ atomic_set(&mddev->bitmap_file->f_dentry->d_inode->i_writecount, 1);
+ fput(mddev->bitmap_file);
+ mddev->bitmap_file = NULL;
+ }
+ mddev->bitmap_offset = 0;
+
ITERATE_RDEV(mddev,rdev,tmp)
if (rdev->raid_disk >= 0) {
char nm[20];
@@ -2939,6 +2944,8 @@ static int get_array_info(mddev_t * mddev, void __user * arg)
info.ctime = mddev->ctime;
info.level = mddev->level;
info.size = mddev->size;
+ if (info.size != mddev->size) /* overflow */
+ info.size = -1;
info.nr_disks = nr;
info.raid_disks = mddev->raid_disks;
info.md_minor = mddev->md_minor;
@@ -3465,7 +3472,7 @@ static int update_size(mddev_t *mddev, unsigned long size)
bdev = bdget_disk(mddev->gendisk, 0);
if (bdev) {
mutex_lock(&bdev->bd_inode->i_mutex);
- i_size_write(bdev->bd_inode, mddev->array_size << 10);
+ i_size_write(bdev->bd_inode, (loff_t)mddev->array_size << 10);
mutex_unlock(&bdev->bd_inode->i_mutex);
bdput(bdev);
}
@@ -3485,17 +3492,6 @@ static int update_raid_disks(mddev_t *mddev, int raid_disks)
if (mddev->sync_thread)
return -EBUSY;
rv = mddev->pers->reshape(mddev, raid_disks);
- if (!rv) {
- struct block_device *bdev;
-
- bdev = bdget_disk(mddev->gendisk, 0);
- if (bdev) {
- mutex_lock(&bdev->bd_inode->i_mutex);
- i_size_write(bdev->bd_inode, mddev->array_size << 10);
- mutex_unlock(&bdev->bd_inode->i_mutex);
- bdput(bdev);
- }
- }
return rv;
}
@@ -3531,7 +3527,7 @@ static int update_array_info(mddev_t *mddev, mdu_array_info_t *info)
)
return -EINVAL;
/* Check there is only one change */
- if (mddev->size != info->size) cnt++;
+ if (info->size >= 0 && mddev->size != info->size) cnt++;
if (mddev->raid_disks != info->raid_disks) cnt++;
if (mddev->layout != info->layout) cnt++;
if ((state ^ info->state) & (1<<MD_SB_BITMAP_PRESENT)) cnt++;
@@ -3548,7 +3544,7 @@ static int update_array_info(mddev_t *mddev, mdu_array_info_t *info)
else
return mddev->pers->reconfig(mddev, info->layout, -1);
}
- if (mddev->size != info->size)
+ if (info->size >= 0 && mddev->size != info->size)
rv = update_size(mddev, info->size);
if (mddev->raid_disks != info->raid_disks)
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index d03f99cf4b7..678f4dbbea1 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -372,7 +372,7 @@ out_free_conf:
kfree(conf);
mddev->private = NULL;
out:
- return 1;
+ return -ENOMEM;
}
static int raid0_stop (mddev_t *mddev)
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 9130d051b47..ab90a6d1202 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -565,6 +565,8 @@ rb_out:
if (disk >= 0 && (rdev=rcu_dereference(conf->mirrors[disk].rdev))!= NULL)
atomic_inc(&conf->mirrors[disk].rdev->nr_pending);
+ else
+ disk = -1;
rcu_read_unlock();
return disk;
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 25976bfb6f9..2dba305daf3 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -350,7 +350,8 @@ static void shrink_stripes(raid5_conf_t *conf)
while (drop_one_stripe(conf))
;
- kmem_cache_destroy(conf->slab_cache);
+ if (conf->slab_cache)
+ kmem_cache_destroy(conf->slab_cache);
conf->slab_cache = NULL;
}
diff --git a/drivers/md/raid6main.c b/drivers/md/raid6main.c
index f618a53b98b..cd477ebf2ee 100644
--- a/drivers/md/raid6main.c
+++ b/drivers/md/raid6main.c
@@ -115,7 +115,7 @@ static void __release_stripe(raid6_conf_t *conf, struct stripe_head *sh)
list_add_tail(&sh->lru, &conf->inactive_list);
atomic_dec(&conf->active_stripes);
if (!conf->inactive_blocked ||
- atomic_read(&conf->active_stripes) < (NR_STRIPES*3/4))
+ atomic_read(&conf->active_stripes) < (conf->max_nr_stripes*3/4))
wake_up(&conf->wait_for_stripe);
}
}
@@ -273,7 +273,8 @@ static struct stripe_head *get_active_stripe(raid6_conf_t *conf, sector_t sector
conf->inactive_blocked = 1;
wait_event_lock_irq(conf->wait_for_stripe,
!list_empty(&conf->inactive_list) &&
- (atomic_read(&conf->active_stripes) < (NR_STRIPES *3/4)
+ (atomic_read(&conf->active_stripes)
+ < (conf->max_nr_stripes *3/4)
|| !conf->inactive_blocked),
conf->device_lock,
unplug_slaves(conf->mddev);
@@ -302,9 +303,31 @@ static struct stripe_head *get_active_stripe(raid6_conf_t *conf, sector_t sector
return sh;
}
-static int grow_stripes(raid6_conf_t *conf, int num)
+static int grow_one_stripe(raid6_conf_t *conf)
{
struct stripe_head *sh;
+ sh = kmem_cache_alloc(conf->slab_cache, GFP_KERNEL);
+ if (!sh)
+ return 0;
+ memset(sh, 0, sizeof(*sh) + (conf->raid_disks-1)*sizeof(struct r5dev));
+ sh->raid_conf = conf;
+ spin_lock_init(&sh->lock);
+
+ if (grow_buffers(sh, conf->raid_disks)) {
+ shrink_buffers(sh, conf->raid_disks);
+ kmem_cache_free(conf->slab_cache, sh);
+ return 0;
+ }
+ /* we just created an active stripe so... */
+ atomic_set(&sh->count, 1);
+ atomic_inc(&conf->active_stripes);
+ INIT_LIST_HEAD(&sh->lru);
+ release_stripe(sh);
+ return 1;
+}
+
+static int grow_stripes(raid6_conf_t *conf, int num)
+{
kmem_cache_t *sc;
int devs = conf->raid_disks;
@@ -316,45 +339,35 @@ static int grow_stripes(raid6_conf_t *conf, int num)
if (!sc)
return 1;
conf->slab_cache = sc;
- while (num--) {
- sh = kmem_cache_alloc(sc, GFP_KERNEL);
- if (!sh)
- return 1;
- memset(sh, 0, sizeof(*sh) + (devs-1)*sizeof(struct r5dev));
- sh->raid_conf = conf;
- spin_lock_init(&sh->lock);
-
- if (grow_buffers(sh, conf->raid_disks)) {
- shrink_buffers(sh, conf->raid_disks);
- kmem_cache_free(sc, sh);
+ while (num--)
+ if (!grow_one_stripe(conf))
return 1;
- }
- /* we just created an active stripe so... */
- atomic_set(&sh->count, 1);
- atomic_inc(&conf->active_stripes);
- INIT_LIST_HEAD(&sh->lru);
- release_stripe(sh);
- }
return 0;
}
-static void shrink_stripes(raid6_conf_t *conf)
+static int drop_one_stripe(raid6_conf_t *conf)
{
struct stripe_head *sh;
+ spin_lock_irq(&conf->device_lock);
+ sh = get_free_stripe(conf);
+ spin_unlock_irq(&conf->device_lock);
+ if (!sh)
+ return 0;
+ if (atomic_read(&sh->count))
+ BUG();
+ shrink_buffers(sh, conf->raid_disks);
+ kmem_cache_free(conf->slab_cache, sh);
+ atomic_dec(&conf->active_stripes);
+ return 1;
+}
- while (1) {
- spin_lock_irq(&conf->device_lock);
- sh = get_free_stripe(conf);
- spin_unlock_irq(&conf->device_lock);
- if (!sh)
- break;
- if (atomic_read(&sh->count))
- BUG();
- shrink_buffers(sh, conf->raid_disks);
- kmem_cache_free(conf->slab_cache, sh);
- atomic_dec(&conf->active_stripes);
- }
- kmem_cache_destroy(conf->slab_cache);
+static void shrink_stripes(raid6_conf_t *conf)
+{
+ while (drop_one_stripe(conf))
+ ;
+
+ if (conf->slab_cache)
+ kmem_cache_destroy(conf->slab_cache);
conf->slab_cache = NULL;
}
@@ -1912,6 +1925,74 @@ static void raid6d (mddev_t *mddev)
PRINTK("--- raid6d inactive\n");
}
+static ssize_t
+raid6_show_stripe_cache_size(mddev_t *mddev, char *page)
+{
+ raid6_conf_t *conf = mddev_to_conf(mddev);
+ if (conf)
+ return sprintf(page, "%d\n", conf->max_nr_stripes);
+ else
+ return 0;
+}
+
+static ssize_t
+raid6_store_stripe_cache_size(mddev_t *mddev, const char *page, size_t len)
+{
+ raid6_conf_t *conf = mddev_to_conf(mddev);
+ char *end;
+ int new;
+ if (len >= PAGE_SIZE)
+ return -EINVAL;
+ if (!conf)
+ return -ENODEV;
+
+ new = simple_strtoul(page, &end, 10);
+ if (!*page || (*end && *end != '\n') )
+ return -EINVAL;
+ if (new <= 16 || new > 32768)
+ return -EINVAL;
+ while (new < conf->max_nr_stripes) {
+ if (drop_one_stripe(conf))
+ conf->max_nr_stripes--;
+ else
+ break;
+ }
+ while (new > conf->max_nr_stripes) {
+ if (grow_one_stripe(conf))
+ conf->max_nr_stripes++;
+ else break;
+ }
+ return len;
+}
+
+static struct md_sysfs_entry
+raid6_stripecache_size = __ATTR(stripe_cache_size, S_IRUGO | S_IWUSR,
+ raid6_show_stripe_cache_size,
+ raid6_store_stripe_cache_size);
+
+static ssize_t
+stripe_cache_active_show(mddev_t *mddev, char *page)
+{
+ raid6_conf_t *conf = mddev_to_conf(mddev);
+ if (conf)
+ return sprintf(page, "%d\n", atomic_read(&conf->active_stripes));
+ else
+ return 0;
+}
+
+static struct md_sysfs_entry
+raid6_stripecache_active = __ATTR_RO(stripe_cache_active);
+
+static struct attribute *raid6_attrs[] = {
+ &raid6_stripecache_size.attr,
+ &raid6_stripecache_active.attr,
+ NULL,
+};
+static struct attribute_group raid6_attrs_group = {
+ .name = NULL,
+ .attrs = raid6_attrs,
+};
+
static int run(mddev_t *mddev)
{
raid6_conf_t *conf;
@@ -2095,6 +2176,7 @@ static int stop (mddev_t *mddev)
shrink_stripes(conf);
kfree(conf->stripe_hashtbl);
blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
+ sysfs_remove_group(&mddev->kobj, &raid6_attrs_group);
kfree(conf);
mddev->private = NULL;
return 0;
diff --git a/drivers/message/i2o/core.h b/drivers/message/i2o/core.h
index 90628562851..184974cc734 100644
--- a/drivers/message/i2o/core.h
+++ b/drivers/message/i2o/core.h
@@ -60,4 +60,7 @@ extern void i2o_iop_remove(struct i2o_controller *);
#define I2O_IN_PORT 0x40
#define I2O_OUT_PORT 0x44
+/* Motorola/Freescale specific register offset */
+#define I2O_MOTOROLA_PORT_OFFSET 0x10400
+
#define I2O_IRQ_OUTBOUND_POST 0x00000008
diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c
index f9e5a23697a..c08ddac3717 100644
--- a/drivers/message/i2o/i2o_scsi.c
+++ b/drivers/message/i2o/i2o_scsi.c
@@ -732,7 +732,7 @@ static int i2o_scsi_abort(struct scsi_cmnd *SCpnt)
cpu_to_le32(I2O_CMD_SCSI_ABORT << 24 | HOST_TID << 12 | tid);
msg->body[0] = cpu_to_le32(i2o_cntxt_list_get_ptr(c, SCpnt));
- if (i2o_msg_post_wait(c, msg, I2O_TIMEOUT_SCSI_SCB_ABORT))
+ if (!i2o_msg_post_wait(c, msg, I2O_TIMEOUT_SCSI_SCB_ABORT))
status = SUCCESS;
return status;
diff --git a/drivers/message/i2o/pci.c b/drivers/message/i2o/pci.c
index d698d7709c3..4f1515cae5d 100644
--- a/drivers/message/i2o/pci.c
+++ b/drivers/message/i2o/pci.c
@@ -88,6 +88,11 @@ static int __devinit i2o_pci_alloc(struct i2o_controller *c)
struct device *dev = &pdev->dev;
int i;
+ if (pci_request_regions(pdev, OSM_DESCRIPTION)) {
+ printk(KERN_ERR "%s: device already claimed\n", c->name);
+ return -ENODEV;
+ }
+
for (i = 0; i < 6; i++) {
/* Skip I/O spaces */
if (!(pci_resource_flags(pdev, i) & IORESOURCE_IO)) {
@@ -163,6 +168,24 @@ static int __devinit i2o_pci_alloc(struct i2o_controller *c)
c->in_port = c->base.virt + I2O_IN_PORT;
c->out_port = c->base.virt + I2O_OUT_PORT;
+ /* Motorola/Freescale chip does not follow spec */
+ if (pdev->vendor == PCI_VENDOR_ID_MOTOROLA && pdev->device == 0x18c0) {
+ /* Check if CPU is enabled */
+ if (be32_to_cpu(readl(c->base.virt + 0x10000)) & 0x10000000) {
+ printk(KERN_INFO "%s: MPC82XX needs CPU running to "
+ "service I2O.\n", c->name);
+ i2o_pci_free(c);
+ return -ENODEV;
+ } else {
+ c->irq_status += I2O_MOTOROLA_PORT_OFFSET;
+ c->irq_mask += I2O_MOTOROLA_PORT_OFFSET;
+ c->in_port += I2O_MOTOROLA_PORT_OFFSET;
+ c->out_port += I2O_MOTOROLA_PORT_OFFSET;
+ printk(KERN_INFO "%s: MPC82XX workarounds activated.\n",
+ c->name);
+ }
+ }
+
if (i2o_dma_alloc(dev, &c->status, 8, GFP_KERNEL)) {
i2o_pci_free(c);
return -ENOMEM;
@@ -298,7 +321,7 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev,
struct i2o_controller *c;
int rc;
struct pci_dev *i960 = NULL;
- int pci_dev_busy = 0;
+ int enabled = pdev->is_enabled;
printk(KERN_INFO "i2o: Checking for PCI I2O controllers...\n");
@@ -308,16 +331,12 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev,
return -ENODEV;
}
- if ((rc = pci_enable_device(pdev))) {
- printk(KERN_WARNING "i2o: couldn't enable device %s\n",
- pci_name(pdev));
- return rc;
- }
-
- if (pci_request_regions(pdev, OSM_DESCRIPTION)) {
- printk(KERN_ERR "i2o: device already claimed\n");
- return -ENODEV;
- }
+ if (!enabled)
+ if ((rc = pci_enable_device(pdev))) {
+ printk(KERN_WARNING "i2o: couldn't enable device %s\n",
+ pci_name(pdev));
+ return rc;
+ }
if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
printk(KERN_WARNING "i2o: no suitable DMA found for %s\n",
@@ -395,9 +414,7 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev,
if ((rc = i2o_pci_alloc(c))) {
printk(KERN_ERR "%s: DMA / IO allocation for I2O controller "
- " failed\n", c->name);
- if (rc == -ENODEV)
- pci_dev_busy = 1;
+ "failed\n", c->name);
goto free_controller;
}
@@ -425,7 +442,7 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev,
i2o_iop_free(c);
disable:
- if (!pci_dev_busy)
+ if (!enabled)
pci_disable_device(pdev);
return rc;
diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c
index aaf04638054..227c39a7c1b 100644
--- a/drivers/mmc/au1xmmc.c
+++ b/drivers/mmc/au1xmmc.c
@@ -194,7 +194,7 @@ static int au1xmmc_send_command(struct au1xmmc_host *host, int wait,
u32 mmccmd = (cmd->opcode << SD_CMD_CI_SHIFT);
- switch(cmd->flags) {
+ switch (mmc_rsp_type(cmd->flags)) {
case MMC_RSP_R1:
mmccmd |= SD_CMD_RT_1;
break;
@@ -483,34 +483,35 @@ static void au1xmmc_cmd_complete(struct au1xmmc_host *host, u32 status)
cmd = mrq->cmd;
cmd->error = MMC_ERR_NONE;
- if ((cmd->flags & MMC_RSP_MASK) == MMC_RSP_SHORT) {
-
- /* Techincally, we should be getting all 48 bits of the response
- * (SD_RESP1 + SD_RESP2), but because our response omits the CRC,
- * our data ends up being shifted 8 bits to the right. In this case,
- * that means that the OSR data starts at bit 31, so we can just
- * read RESP0 and return that
- */
-
- cmd->resp[0] = au_readl(host->iobase + SD_RESP0);
- }
- else if ((cmd->flags & MMC_RSP_MASK) == MMC_RSP_LONG) {
- u32 r[4];
- int i;
-
- r[0] = au_readl(host->iobase + SD_RESP3);
- r[1] = au_readl(host->iobase + SD_RESP2);
- r[2] = au_readl(host->iobase + SD_RESP1);
- r[3] = au_readl(host->iobase + SD_RESP0);
-
- /* The CRC is omitted from the response, so really we only got
- * 120 bytes, but the engine expects 128 bits, so we have to shift
- * things up
- */
-
- for(i = 0; i < 4; i++) {
- cmd->resp[i] = (r[i] & 0x00FFFFFF) << 8;
- if (i != 3) cmd->resp[i] |= (r[i + 1] & 0xFF000000) >> 24;
+ if (cmd->flags & MMC_RSP_PRESENT) {
+ if (cmd->flags & MMC_RSP_136) {
+ u32 r[4];
+ int i;
+
+ r[0] = au_readl(host->iobase + SD_RESP3);
+ r[1] = au_readl(host->iobase + SD_RESP2);
+ r[2] = au_readl(host->iobase + SD_RESP1);
+ r[3] = au_readl(host->iobase + SD_RESP0);
+
+ /* The CRC is omitted from the response, so really
+ * we only got 120 bytes, but the engine expects
+ * 128 bits, so we have to shift things up
+ */
+
+ for(i = 0; i < 4; i++) {
+ cmd->resp[i] = (r[i] & 0x00FFFFFF) << 8;
+ if (i != 3)
+ cmd->resp[i] |= (r[i + 1] & 0xFF000000) >> 24;
+ }
+ } else {
+ /* Techincally, we should be getting all 48 bits of
+ * the response (SD_RESP1 + SD_RESP2), but because
+ * our response omits the CRC, our data ends up
+ * being shifted 8 bits to the right. In this case,
+ * that means that the OSR data starts at bit 31,
+ * so we can just read RESP0 and return that
+ */
+ cmd->resp[0] = au_readl(host->iobase + SD_RESP0);
}
}
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index bfca5c176e8..1888060c5e0 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -211,7 +211,7 @@ int mmc_wait_for_app_cmd(struct mmc_host *host, unsigned int rca,
appcmd.opcode = MMC_APP_CMD;
appcmd.arg = rca << 16;
- appcmd.flags = MMC_RSP_R1;
+ appcmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
appcmd.retries = 0;
memset(appcmd.resp, 0, sizeof(appcmd.resp));
appcmd.data = NULL;
@@ -331,7 +331,7 @@ static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
cmd.opcode = MMC_SELECT_CARD;
cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
if (err != MMC_ERR_NONE)
@@ -358,7 +358,7 @@ static int mmc_select_card(struct mmc_host *host, struct mmc_card *card)
struct mmc_command cmd;
cmd.opcode = SD_APP_SET_BUS_WIDTH;
cmd.arg = SD_BUS_WIDTH_4;
- cmd.flags = MMC_RSP_R1;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_app_cmd(host, card->rca, &cmd,
CMD_RETRIES);
@@ -386,7 +386,7 @@ static void mmc_deselect_cards(struct mmc_host *host)
cmd.opcode = MMC_SELECT_CARD;
cmd.arg = 0;
- cmd.flags = MMC_RSP_NONE;
+ cmd.flags = MMC_RSP_NONE | MMC_CMD_AC;
mmc_wait_for_cmd(host, &cmd, 0);
}
@@ -677,7 +677,7 @@ static void mmc_idle_cards(struct mmc_host *host)
cmd.opcode = MMC_GO_IDLE_STATE;
cmd.arg = 0;
- cmd.flags = MMC_RSP_NONE;
+ cmd.flags = MMC_RSP_NONE | MMC_CMD_BC;
mmc_wait_for_cmd(host, &cmd, 0);
@@ -738,7 +738,7 @@ static int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
cmd.opcode = MMC_SEND_OP_COND;
cmd.arg = ocr;
- cmd.flags = MMC_RSP_R3;
+ cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
for (i = 100; i; i--) {
err = mmc_wait_for_cmd(host, &cmd, 0);
@@ -766,7 +766,7 @@ static int mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr)
cmd.opcode = SD_APP_OP_COND;
cmd.arg = ocr;
- cmd.flags = MMC_RSP_R3;
+ cmd.flags = MMC_RSP_R3 | MMC_CMD_BCR;
for (i = 100; i; i--) {
err = mmc_wait_for_app_cmd(host, 0, &cmd, CMD_RETRIES);
@@ -805,7 +805,7 @@ static void mmc_discover_cards(struct mmc_host *host)
cmd.opcode = MMC_ALL_SEND_CID;
cmd.arg = 0;
- cmd.flags = MMC_RSP_R2;
+ cmd.flags = MMC_RSP_R2 | MMC_CMD_BCR;
err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
if (err == MMC_ERR_TIMEOUT) {
@@ -835,7 +835,7 @@ static void mmc_discover_cards(struct mmc_host *host)
cmd.opcode = SD_SEND_RELATIVE_ADDR;
cmd.arg = 0;
- cmd.flags = MMC_RSP_R6;
+ cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR;
err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
if (err != MMC_ERR_NONE)
@@ -856,7 +856,7 @@ static void mmc_discover_cards(struct mmc_host *host)
} else {
cmd.opcode = MMC_SET_RELATIVE_ADDR;
cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
if (err != MMC_ERR_NONE)
@@ -878,7 +878,7 @@ static void mmc_read_csds(struct mmc_host *host)
cmd.opcode = MMC_SEND_CSD;
cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R2;
+ cmd.flags = MMC_RSP_R2 | MMC_CMD_AC;
err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
if (err != MMC_ERR_NONE) {
@@ -920,7 +920,7 @@ static void mmc_read_scrs(struct mmc_host *host)
cmd.opcode = MMC_APP_CMD;
cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(host, &cmd, 0);
if ((err != MMC_ERR_NONE) || !(cmd.resp[0] & R1_APP_CMD)) {
@@ -932,7 +932,7 @@ static void mmc_read_scrs(struct mmc_host *host)
cmd.opcode = SD_APP_SEND_SCR;
cmd.arg = 0;
- cmd.flags = MMC_RSP_R1;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
memset(&data, 0, sizeof(struct mmc_data));
@@ -1003,7 +1003,7 @@ static void mmc_check_cards(struct mmc_host *host)
cmd.opcode = MMC_SEND_STATUS;
cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(host, &cmd, CMD_RETRIES);
if (err == MMC_ERR_NONE)
diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c
index 5b014c370e8..8eb2a2ede64 100644
--- a/drivers/mmc/mmc_block.c
+++ b/drivers/mmc/mmc_block.c
@@ -171,14 +171,14 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
brq.mrq.data = &brq.data;
brq.cmd.arg = req->sector << 9;
- brq.cmd.flags = MMC_RSP_R1;
+ brq.cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
brq.data.timeout_ns = card->csd.tacc_ns * 10;
brq.data.timeout_clks = card->csd.tacc_clks * 10;
brq.data.blksz_bits = md->block_bits;
brq.data.blocks = req->nr_sectors >> (md->block_bits - 9);
brq.stop.opcode = MMC_STOP_TRANSMISSION;
brq.stop.arg = 0;
- brq.stop.flags = MMC_RSP_R1B;
+ brq.stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
if (rq_data_dir(req) == READ) {
brq.cmd.opcode = brq.data.blocks > 1 ? MMC_READ_MULTIPLE_BLOCK : MMC_READ_SINGLE_BLOCK;
@@ -223,7 +223,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
cmd.opcode = MMC_SEND_STATUS;
cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_R1;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, 5);
if (err) {
printk(KERN_ERR "%s: error %d requesting status\n",
@@ -430,7 +430,7 @@ mmc_blk_set_blksize(struct mmc_blk_data *md, struct mmc_card *card)
mmc_card_claim_host(card);
cmd.opcode = MMC_SET_BLOCKLEN;
cmd.arg = 1 << md->block_bits;
- cmd.flags = MMC_RSP_R1;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(card->host, &cmd, 5);
mmc_card_release_host(card);
diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c
index 634ef53e85a..37ee7f8dc82 100644
--- a/drivers/mmc/mmci.c
+++ b/drivers/mmc/mmci.c
@@ -124,15 +124,10 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c)
}
c |= cmd->opcode | MCI_CPSM_ENABLE;
- switch (cmd->flags & MMC_RSP_MASK) {
- case MMC_RSP_NONE:
- default:
- break;
- case MMC_RSP_LONG:
- c |= MCI_CPSM_LONGRSP;
- case MMC_RSP_SHORT:
+ if (cmd->flags & MMC_RSP_PRESENT) {
+ if (cmd->flags & MMC_RSP_136)
+ c |= MCI_CPSM_LONGRSP;
c |= MCI_CPSM_RESPONSE;
- break;
}
if (/*interrupt*/0)
c |= MCI_CPSM_INTERRUPT;
diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c
index ee8f8a0420d..285d7d06809 100644
--- a/drivers/mmc/pxamci.c
+++ b/drivers/mmc/pxamci.c
@@ -178,14 +178,15 @@ static void pxamci_start_cmd(struct pxamci_host *host, struct mmc_command *cmd,
if (cmd->flags & MMC_RSP_BUSY)
cmdat |= CMDAT_BUSY;
- switch (cmd->flags & (MMC_RSP_MASK | MMC_RSP_CRC)) {
- case MMC_RSP_SHORT | MMC_RSP_CRC:
+#define RSP_TYPE(x) ((x) & ~(MMC_RSP_BUSY|MMC_RSP_OPCODE))
+ switch (RSP_TYPE(mmc_resp_type(cmd))) {
+ case RSP_TYPE(MMC_RSP_R1): /* r1, r1b, r6 */
cmdat |= CMDAT_RESP_SHORT;
break;
- case MMC_RSP_SHORT:
+ case RSP_TYPE(MMC_RSP_R3):
cmdat |= CMDAT_RESP_R3;
break;
- case MMC_RSP_LONG | MMC_RSP_CRC:
+ case RSP_TYPE(MMC_RSP_R2):
cmdat |= CMDAT_RESP_R2;
break;
default:
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c
index f2575762536..3be397d436f 100644
--- a/drivers/mmc/wbsd.c
+++ b/drivers/mmc/wbsd.c
@@ -459,7 +459,7 @@ static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd)
/*
* Do we expect a reply?
*/
- if ((cmd->flags & MMC_RSP_MASK) != MMC_RSP_NONE) {
+ if (cmd->flags & MMC_RSP_PRESENT) {
/*
* Read back status.
*/
@@ -476,10 +476,10 @@ static void wbsd_send_command(struct wbsd_host *host, struct mmc_command *cmd)
cmd->error = MMC_ERR_BADCRC;
/* All ok */
else {
- if ((cmd->flags & MMC_RSP_MASK) == MMC_RSP_SHORT)
- wbsd_get_short_reply(host, cmd);
- else
+ if (cmd->flags & MMC_RSP_136)
wbsd_get_long_reply(host, cmd);
+ else
+ wbsd_get_short_reply(host, cmd);
}
}
diff --git a/drivers/mtd/maps/dc21285.c b/drivers/mtd/maps/dc21285.c
index 701620b6bae..8b3784e2de8 100644
--- a/drivers/mtd/maps/dc21285.c
+++ b/drivers/mtd/maps/dc21285.c
@@ -110,8 +110,9 @@ static void dc21285_copy_to_32(struct map_info *map, unsigned long to, const voi
{
while (len > 0) {
map_word d;
- d.x[0] = *((uint32_t*)from)++;
+ d.x[0] = *((uint32_t*)from);
dc21285_write32(map, d, to);
+ from += 4;
to += 4;
len -= 4;
}
@@ -121,8 +122,9 @@ static void dc21285_copy_to_16(struct map_info *map, unsigned long to, const voi
{
while (len > 0) {
map_word d;
- d.x[0] = *((uint16_t*)from)++;
+ d.x[0] = *((uint16_t*)from);
dc21285_write16(map, d, to);
+ from += 2;
to += 2;
len -= 2;
}
@@ -131,8 +133,9 @@ static void dc21285_copy_to_16(struct map_info *map, unsigned long to, const voi
static void dc21285_copy_to_8(struct map_info *map, unsigned long to, const void *from, ssize_t len)
{
map_word d;
- d.x[0] = *((uint8_t*)from)++;
+ d.x[0] = *((uint8_t*)from);
dc21285_write8(map, d, to);
+ from++;
to++;
len--;
}
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 7488ee7f7ca..7f47124f118 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -753,9 +753,11 @@ enum tx_desc_status {
enum ChipCaps { CapBusMaster=0x20, CapPwrMgmt=0x2000 };
struct vortex_extra_stats {
- unsigned long tx_deferred;
- unsigned long tx_multiple_collisions;
- unsigned long rx_bad_ssd;
+ unsigned long tx_deferred;
+ unsigned long tx_max_collisions;
+ unsigned long tx_multiple_collisions;
+ unsigned long tx_single_collisions;
+ unsigned long rx_bad_ssd;
};
struct vortex_private {
@@ -863,12 +865,14 @@ static struct {
const char str[ETH_GSTRING_LEN];
} ethtool_stats_keys[] = {
{ "tx_deferred" },
+ { "tx_max_collisions" },
{ "tx_multiple_collisions" },
+ { "tx_single_collisions" },
{ "rx_bad_ssd" },
};
/* number of ETHTOOL_GSTATS u64's */
-#define VORTEX_NUM_STATS 3
+#define VORTEX_NUM_STATS 5
static int vortex_probe1(struct device *gendev, void __iomem *ioaddr, int irq,
int chip_idx, int card_idx);
@@ -2108,9 +2112,12 @@ vortex_error(struct net_device *dev, int status)
iowrite8(0, ioaddr + TxStatus);
if (tx_status & 0x30) { /* txJabber or txUnderrun */
do_tx_reset = 1;
- } else if ((tx_status & 0x08) && (vp->drv_flags & MAX_COLLISION_RESET)) { /* maxCollisions */
- do_tx_reset = 1;
- reset_mask = 0x0108; /* Reset interface logic, but not download logic */
+ } else if (tx_status & 0x08) { /* maxCollisions */
+ vp->xstats.tx_max_collisions++;
+ if (vp->drv_flags & MAX_COLLISION_RESET) {
+ do_tx_reset = 1;
+ reset_mask = 0x0108; /* Reset interface logic, but not download logic */
+ }
} else { /* Merely re-enable the transmitter. */
iowrite16(TxEnable, ioaddr + EL3_CMD);
}
@@ -2926,7 +2933,6 @@ static void update_stats(void __iomem *ioaddr, struct net_device *dev)
EL3WINDOW(6);
vp->stats.tx_carrier_errors += ioread8(ioaddr + 0);
vp->stats.tx_heartbeat_errors += ioread8(ioaddr + 1);
- vp->stats.collisions += ioread8(ioaddr + 3);
vp->stats.tx_window_errors += ioread8(ioaddr + 4);
vp->stats.rx_fifo_errors += ioread8(ioaddr + 5);
vp->stats.tx_packets += ioread8(ioaddr + 6);
@@ -2939,10 +2945,15 @@ static void update_stats(void __iomem *ioaddr, struct net_device *dev)
vp->stats.tx_bytes += ioread16(ioaddr + 12);
/* Extra stats for get_ethtool_stats() */
vp->xstats.tx_multiple_collisions += ioread8(ioaddr + 2);
+ vp->xstats.tx_single_collisions += ioread8(ioaddr + 3);
vp->xstats.tx_deferred += ioread8(ioaddr + 8);
EL3WINDOW(4);
vp->xstats.rx_bad_ssd += ioread8(ioaddr + 12);
+ vp->stats.collisions = vp->xstats.tx_multiple_collisions
+ + vp->xstats.tx_single_collisions
+ + vp->xstats.tx_max_collisions;
+
{
u8 up = ioread8(ioaddr + 13);
vp->stats.rx_bytes += (up & 0x0f) << 16;
@@ -3036,8 +3047,10 @@ static void vortex_get_ethtool_stats(struct net_device *dev,
spin_unlock_irqrestore(&vp->lock, flags);
data[0] = vp->xstats.tx_deferred;
- data[1] = vp->xstats.tx_multiple_collisions;
- data[2] = vp->xstats.rx_bad_ssd;
+ data[1] = vp->xstats.tx_max_collisions;
+ data[2] = vp->xstats.tx_multiple_collisions;
+ data[3] = vp->xstats.tx_single_collisions;
+ data[4] = vp->xstats.rx_bad_ssd;
}
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index 1c6d328165b..0245e40b51a 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -1610,6 +1610,8 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
}
else if (!pskb_may_pull(skb, skb->len))
goto err;
+ else
+ skb->ip_summed = CHECKSUM_NONE;
len = slhc_uncompress(ppp->vj, skb->data + 2, skb->len - 2);
if (len <= 0) {
@@ -1690,6 +1692,7 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb)
kfree_skb(skb);
} else {
skb_pull(skb, 2); /* chop off protocol */
+ skb_postpull_rcsum(skb, skb->data - 2, 2);
skb->dev = ppp->dev;
skb->protocol = htons(npindex_to_ethertype[npi]);
skb->mac.raw = skb->data;
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index f2d1dafde08..e7dc653d5bd 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -69,8 +69,8 @@
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "3.48"
-#define DRV_MODULE_RELDATE "Jan 16, 2006"
+#define DRV_MODULE_VERSION "3.49"
+#define DRV_MODULE_RELDATE "Feb 2, 2006"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -3482,6 +3482,17 @@ static void tg3_reset_task(void *_data)
struct tg3 *tp = _data;
unsigned int restart_timer;
+ tg3_full_lock(tp, 0);
+ tp->tg3_flags |= TG3_FLAG_IN_RESET_TASK;
+
+ if (!netif_running(tp->dev)) {
+ tp->tg3_flags &= ~TG3_FLAG_IN_RESET_TASK;
+ tg3_full_unlock(tp);
+ return;
+ }
+
+ tg3_full_unlock(tp);
+
tg3_netif_stop(tp);
tg3_full_lock(tp, 1);
@@ -3494,10 +3505,12 @@ static void tg3_reset_task(void *_data)
tg3_netif_start(tp);
- tg3_full_unlock(tp);
-
if (restart_timer)
mod_timer(&tp->timer, jiffies + 1);
+
+ tp->tg3_flags &= ~TG3_FLAG_IN_RESET_TASK;
+
+ tg3_full_unlock(tp);
}
static void tg3_tx_timeout(struct net_device *dev)
@@ -6786,6 +6799,13 @@ static int tg3_close(struct net_device *dev)
{
struct tg3 *tp = netdev_priv(dev);
+ /* Calling flush_scheduled_work() may deadlock because
+ * linkwatch_event() may be on the workqueue and it will try to get
+ * the rtnl_lock which we are holding.
+ */
+ while (tp->tg3_flags & TG3_FLAG_IN_RESET_TASK)
+ msleep(1);
+
netif_stop_queue(dev);
del_timer_sync(&tp->timer);
@@ -10880,6 +10900,7 @@ static void __devexit tg3_remove_one(struct pci_dev *pdev)
if (dev) {
struct tg3 *tp = netdev_priv(dev);
+ flush_scheduled_work();
unregister_netdev(dev);
if (tp->regs) {
iounmap(tp->regs);
@@ -10901,6 +10922,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
if (!netif_running(dev))
return 0;
+ flush_scheduled_work();
tg3_netif_stop(tp);
del_timer_sync(&tp->timer);
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index e8243305f0e..7f4b7f6ac40 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -2162,6 +2162,7 @@ struct tg3 {
#define TG3_FLAG_JUMBO_RING_ENABLE 0x00800000
#define TG3_FLAG_10_100_ONLY 0x01000000
#define TG3_FLAG_PAUSE_AUTONEG 0x02000000
+#define TG3_FLAG_IN_RESET_TASK 0x04000000
#define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000
#define TG3_FLAG_GOT_SERDES_FLOWCTL 0x20000000
#define TG3_FLAG_SPLIT_MODE 0x40000000
diff --git a/drivers/parisc/ccio-dma.c b/drivers/parisc/ccio-dma.c
index 9e0229f7e25..f46e8438e0d 100644
--- a/drivers/parisc/ccio-dma.c
+++ b/drivers/parisc/ccio-dma.c
@@ -1423,7 +1423,7 @@ static void __init ccio_init_resources(struct ioc *ioc)
struct resource *res = ioc->mmio_region;
char *name = kmalloc(14, GFP_KERNEL);
- sprintf(name, "GSC Bus [%d/]", ioc->hw_path);
+ snprintf(name, 14, "GSC Bus [%d/]", ioc->hw_path);
ccio_init_resource(res, name, &ioc->ioc_regs->io_io_low);
ccio_init_resource(res + 1, name, &ioc->ioc_regs->io_io_low_hv);
@@ -1557,12 +1557,11 @@ static int ccio_probe(struct parisc_device *dev)
int i;
struct ioc *ioc, **ioc_p = &ioc_list;
- ioc = kmalloc(sizeof(struct ioc), GFP_KERNEL);
+ ioc = kzalloc(sizeof(struct ioc), GFP_KERNEL);
if (ioc == NULL) {
printk(KERN_ERR MODULE_NAME ": memory allocation failure\n");
return 1;
}
- memset(ioc, 0, sizeof(struct ioc));
ioc->name = dev->id.hversion == U2_IOA_RUNWAY ? "U2" : "UTurn";
@@ -1578,7 +1577,7 @@ static int ccio_probe(struct parisc_device *dev)
ccio_ioc_init(ioc);
ccio_init_resources(ioc);
hppa_dma_ops = &ccio_ops;
- dev->dev.platform_data = kmalloc(sizeof(struct pci_hba_data), GFP_KERNEL);
+ dev->dev.platform_data = kzalloc(sizeof(struct pci_hba_data), GFP_KERNEL);
/* if this fails, no I/O cards will work, so may as well bug */
BUG_ON(dev->dev.platform_data == NULL);
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index 216d1d85932..3d1a7f98c67 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -989,14 +989,12 @@ static int __init dino_probe(struct parisc_device *dev)
*/
}
- dino_dev = kmalloc(sizeof(struct dino_device), GFP_KERNEL);
+ dino_dev = kzalloc(sizeof(struct dino_device), GFP_KERNEL);
if (!dino_dev) {
printk("dino_init_chip - couldn't alloc dino_device\n");
return 1;
}
- memset(dino_dev, 0, sizeof(struct dino_device));
-
dino_dev->hba.dev = dev;
dino_dev->hba.base_addr = ioremap(hpa, 4096);
dino_dev->hba.lmmio_space_offset = 0; /* CPU addrs == bus addrs */
diff --git a/drivers/parisc/hppb.c b/drivers/parisc/hppb.c
index 5edf93f8075..07dc2b6d4e9 100644
--- a/drivers/parisc/hppb.c
+++ b/drivers/parisc/hppb.c
@@ -60,12 +60,11 @@ static int hppb_probe(struct parisc_device *dev)
}
if(card->hpa) {
- card->next = kmalloc(sizeof(struct hppb_card), GFP_KERNEL);
+ card->next = kzalloc(sizeof(struct hppb_card), GFP_KERNEL);
if(!card->next) {
printk(KERN_ERR "HP-PB: Unable to allocate memory.\n");
return 1;
}
- memset(card->next, '\0', sizeof(struct hppb_card));
card = card->next;
}
printk(KERN_INFO "Found GeckoBoa at 0x%lx\n", dev->hpa.start);
diff --git a/drivers/parisc/iosapic.c b/drivers/parisc/iosapic.c
index 19657efa8dc..8d7a36392eb 100644
--- a/drivers/parisc/iosapic.c
+++ b/drivers/parisc/iosapic.c
@@ -873,28 +873,24 @@ void *iosapic_register(unsigned long hpa)
return NULL;
}
- isi = (struct iosapic_info *)kmalloc(sizeof(struct iosapic_info), GFP_KERNEL);
+ isi = (struct iosapic_info *)kzalloc(sizeof(struct iosapic_info), GFP_KERNEL);
if (!isi) {
BUG();
return NULL;
}
- memset(isi, 0, sizeof(struct iosapic_info));
-
isi->addr = ioremap(hpa, 4096);
isi->isi_hpa = hpa;
isi->isi_version = iosapic_rd_version(isi);
isi->isi_num_vectors = IOSAPIC_IRDT_MAX_ENTRY(isi->isi_version) + 1;
vip = isi->isi_vector = (struct vector_info *)
- kmalloc(sizeof(struct vector_info) * isi->isi_num_vectors, GFP_KERNEL);
+ kzalloc(sizeof(struct vector_info) * isi->isi_num_vectors, GFP_KERNEL);
if (vip == NULL) {
kfree(isi);
return NULL;
}
- memset(vip, 0, sizeof(struct vector_info) * isi->isi_num_vectors);
-
for (cnt=0; cnt < isi->isi_num_vectors; cnt++, vip++) {
vip->irqline = (unsigned char) cnt;
vip->iosapic = isi;
diff --git a/drivers/parisc/lasi.c b/drivers/parisc/lasi.c
index 2b3ba1dcf33..cb3d2817612 100644
--- a/drivers/parisc/lasi.c
+++ b/drivers/parisc/lasi.c
@@ -166,11 +166,12 @@ static void lasi_power_off(void)
int __init
lasi_init_chip(struct parisc_device *dev)
{
+ extern void (*chassis_power_off)(void);
struct gsc_asic *lasi;
struct gsc_irq gsc_irq;
int ret;
- lasi = kmalloc(sizeof(*lasi), GFP_KERNEL);
+ lasi = kzalloc(sizeof(*lasi), GFP_KERNEL);
if (!lasi)
return -ENOMEM;
@@ -222,7 +223,7 @@ lasi_init_chip(struct parisc_device *dev)
* ensure that only the first LASI (the one controlling the power off)
* should set the HPA here */
lasi_power_off_hpa = lasi->hpa;
- pm_power_off = lasi_power_off;
+ chassis_power_off = lasi_power_off;
return ret;
}
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index cbae8c8963f..e8a2a4a852f 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -1565,7 +1565,7 @@ lba_driver_probe(struct parisc_device *dev)
} else if (IS_MERCURY(dev) || IS_QUICKSILVER(dev)) {
func_class &= 0xff;
version = kmalloc(6, GFP_KERNEL);
- sprintf(version,"TR%d.%d",(func_class >> 4),(func_class & 0xf));
+ snprintf(version, 6, "TR%d.%d",(func_class >> 4),(func_class & 0xf));
/* We could use one printk for both Elroy and Mercury,
* but for the mask for func_class.
*/
@@ -1586,14 +1586,12 @@ lba_driver_probe(struct parisc_device *dev)
** have an IRT entry will get NULL back from iosapic code.
*/
- lba_dev = kmalloc(sizeof(struct lba_device), GFP_KERNEL);
+ lba_dev = kzalloc(sizeof(struct lba_device), GFP_KERNEL);
if (!lba_dev) {
printk(KERN_ERR "lba_init_chip - couldn't alloc lba_device\n");
return(1);
}
- memset(lba_dev, 0, sizeof(struct lba_device));
-
/* ---------- First : initialize data we already have --------- */
diff --git a/drivers/parisc/pdc_stable.c b/drivers/parisc/pdc_stable.c
index 42a3c54e8e6..a28e17898fb 100644
--- a/drivers/parisc/pdc_stable.c
+++ b/drivers/parisc/pdc_stable.c
@@ -1,7 +1,7 @@
/*
* Interfaces to retrieve and set PDC Stable options (firmware)
*
- * Copyright (C) 2005 Thibaut VARENE <varenet@parisc-linux.org>
+ * Copyright (C) 2005-2006 Thibaut VARENE <varenet@parisc-linux.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,11 +26,19 @@
*
* Since locations between 96 and 192 are the various paths, most (if not
* all) PA-RISC machines should have them. Anyway, for safety reasons, the
- * following code can deal with only 96 bytes of Stable Storage, and all
+ * following code can deal with just 96 bytes of Stable Storage, and all
* sizes between 96 and 192 bytes (provided they are multiple of struct
* device_path size, eg: 128, 160 and 192) to provide full information.
* The code makes no use of data above 192 bytes. One last word: there's one
* path we can always count on: the primary path.
+ *
+ * The current policy wrt file permissions is:
+ * - write: root only
+ * - read: (reading triggers PDC calls) ? root only : everyone
+ * The rationale is that PDC calls could hog (DoS) the machine.
+ *
+ * TODO:
+ * - timer/fastsize write calls
*/
#undef PDCS_DEBUG
@@ -50,13 +58,15 @@
#include <linux/kobject.h>
#include <linux/device.h>
#include <linux/errno.h>
+#include <linux/spinlock.h>
#include <asm/pdc.h>
#include <asm/page.h>
#include <asm/uaccess.h>
#include <asm/hardware.h>
-#define PDCS_VERSION "0.10"
+#define PDCS_VERSION "0.22"
+#define PDCS_PREFIX "PDC Stable Storage"
#define PDCS_ADDR_PPRI 0x00
#define PDCS_ADDR_OSID 0x40
@@ -70,10 +80,12 @@ MODULE_DESCRIPTION("sysfs interface to HP PDC Stable Storage data");
MODULE_LICENSE("GPL");
MODULE_VERSION(PDCS_VERSION);
+/* holds Stable Storage size. Initialized once and for all, no lock needed */
static unsigned long pdcs_size __read_mostly;
/* This struct defines what we need to deal with a parisc pdc path entry */
struct pdcspath_entry {
+ rwlock_t rw_lock; /* to protect path entry access */
short ready; /* entry record is valid if != 0 */
unsigned long addr; /* entry address in stable storage */
char *name; /* entry name */
@@ -121,6 +133,8 @@ struct pdcspath_attribute paths_attr_##_name = { \
* content of the stable storage WRT various paths in these structs. We read
* these structs when reading the files, and we will write to these structs when
* writing to the files, and only then write them back to the Stable Storage.
+ *
+ * This function expects to be called with @entry->rw_lock write-hold.
*/
static int
pdcspath_fetch(struct pdcspath_entry *entry)
@@ -160,14 +174,15 @@ pdcspath_fetch(struct pdcspath_entry *entry)
* pointer, from which it'll find out the corresponding hardware path.
* For now we do not handle the case where there's an error in writing to the
* Stable Storage area, so you'd better not mess up the data :P
+ *
+ * This function expects to be called with @entry->rw_lock write-hold.
*/
-static int
+static void
pdcspath_store(struct pdcspath_entry *entry)
{
struct device_path *devpath;
- if (!entry)
- return -EINVAL;
+ BUG_ON(!entry);
devpath = &entry->devpath;
@@ -176,10 +191,8 @@ pdcspath_store(struct pdcspath_entry *entry)
First case, we don't have a preset hwpath... */
if (!entry->ready) {
/* ...but we have a device, map it */
- if (entry->dev)
- device_to_hwpath(entry->dev, (struct hardware_path *)devpath);
- else
- return -EINVAL;
+ BUG_ON(!entry->dev);
+ device_to_hwpath(entry->dev, (struct hardware_path *)devpath);
}
/* else, we expect the provided hwpath to be valid. */
@@ -191,15 +204,13 @@ pdcspath_store(struct pdcspath_entry *entry)
printk(KERN_ERR "%s: an error occured when writing to PDC.\n"
"It is likely that the Stable Storage data has been corrupted.\n"
"Please check it carefully upon next reboot.\n", __func__);
- return -EIO;
+ WARN_ON(1);
}
/* kobject is already registered */
entry->ready = 2;
DPRINTK("%s: device: 0x%p\n", __func__, entry->dev);
-
- return 0;
}
/**
@@ -214,14 +225,17 @@ pdcspath_hwpath_read(struct pdcspath_entry *entry, char *buf)
{
char *out = buf;
struct device_path *devpath;
- unsigned short i;
+ short i;
if (!entry || !buf)
return -EINVAL;
+ read_lock(&entry->rw_lock);
devpath = &entry->devpath;
+ i = entry->ready;
+ read_unlock(&entry->rw_lock);
- if (!entry->ready)
+ if (!i) /* entry is not ready */
return -ENODATA;
for (i = 0; i < 6; i++) {
@@ -242,7 +256,7 @@ pdcspath_hwpath_read(struct pdcspath_entry *entry, char *buf)
*
* We will call this function to change the current hardware path.
* Hardware paths are to be given '/'-delimited, without brackets.
- * We take care to make sure that the provided path actually maps to an existing
+ * We make sure that the provided path actually maps to an existing
* device, BUT nothing would prevent some foolish user to set the path to some
* PCI bridge or even a CPU...
* A better work around would be to make sure we are at the end of a device tree
@@ -298,17 +312,19 @@ pdcspath_hwpath_write(struct pdcspath_entry *entry, const char *buf, size_t coun
}
/* So far so good, let's get in deep */
+ write_lock(&entry->rw_lock);
entry->ready = 0;
entry->dev = dev;
/* Now, dive in. Write back to the hardware */
- WARN_ON(pdcspath_store(entry)); /* this warn should *NEVER* happen */
+ pdcspath_store(entry);
/* Update the symlink to the real device */
sysfs_remove_link(&entry->kobj, "device");
sysfs_create_link(&entry->kobj, &entry->dev->kobj, "device");
+ write_unlock(&entry->rw_lock);
- printk(KERN_INFO "PDC Stable Storage: changed \"%s\" path to \"%s\"\n",
+ printk(KERN_INFO PDCS_PREFIX ": changed \"%s\" path to \"%s\"\n",
entry->name, buf);
return count;
@@ -326,14 +342,17 @@ pdcspath_layer_read(struct pdcspath_entry *entry, char *buf)
{
char *out = buf;
struct device_path *devpath;
- unsigned short i;
+ short i;
if (!entry || !buf)
return -EINVAL;
+ read_lock(&entry->rw_lock);
devpath = &entry->devpath;
+ i = entry->ready;
+ read_unlock(&entry->rw_lock);
- if (!entry->ready)
+ if (!i) /* entry is not ready */
return -ENODATA;
for (i = 0; devpath->layers[i] && (likely(i < 6)); i++)
@@ -388,15 +407,17 @@ pdcspath_layer_write(struct pdcspath_entry *entry, const char *buf, size_t count
}
/* So far so good, let's get in deep */
+ write_lock(&entry->rw_lock);
/* First, overwrite the current layers with the new ones, not touching
the hardware path. */
memcpy(&entry->devpath.layers, &layers, sizeof(layers));
/* Now, dive in. Write back to the hardware */
- WARN_ON(pdcspath_store(entry)); /* this warn should *NEVER* happen */
+ pdcspath_store(entry);
+ write_unlock(&entry->rw_lock);
- printk(KERN_INFO "PDC Stable Storage: changed \"%s\" layers to \"%s\"\n",
+ printk(KERN_INFO PDCS_PREFIX ": changed \"%s\" layers to \"%s\"\n",
entry->name, buf);
return count;
@@ -415,9 +436,6 @@ pdcspath_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
struct pdcspath_attribute *pdcs_attr = to_pdcspath_attribute(attr);
ssize_t ret = 0;
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
-
if (pdcs_attr->show)
ret = pdcs_attr->show(entry, buf);
@@ -454,8 +472,8 @@ static struct sysfs_ops pdcspath_attr_ops = {
};
/* These are the two attributes of any PDC path. */
-static PATHS_ATTR(hwpath, 0600, pdcspath_hwpath_read, pdcspath_hwpath_write);
-static PATHS_ATTR(layer, 0600, pdcspath_layer_read, pdcspath_layer_write);
+static PATHS_ATTR(hwpath, 0644, pdcspath_hwpath_read, pdcspath_hwpath_write);
+static PATHS_ATTR(layer, 0644, pdcspath_layer_read, pdcspath_layer_write);
static struct attribute *paths_subsys_attrs[] = {
&paths_attr_hwpath.attr,
@@ -484,36 +502,119 @@ static struct pdcspath_entry *pdcspath_entries[] = {
NULL,
};
+
+/* For more insight of what's going on here, refer to PDC Procedures doc,
+ * Section PDC_STABLE */
+
/**
- * pdcs_info_read - Pretty printing of the remaining useful data.
+ * pdcs_size_read - Stable Storage size output.
* @entry: An allocated and populated subsytem struct. We don't use it tho.
* @buf: The output buffer to write to.
- *
- * We will call this function to format the output of the 'info' attribute file.
- * Please refer to PDC Procedures documentation, section PDC_STABLE to get a
- * better insight of what we're doing here.
*/
static ssize_t
-pdcs_info_read(struct subsystem *entry, char *buf)
+pdcs_size_read(struct subsystem *entry, char *buf)
{
char *out = buf;
- __u32 result;
- struct device_path devpath;
- char *tmpstr = NULL;
if (!entry || !buf)
return -EINVAL;
/* show the size of the stable storage */
- out += sprintf(out, "Stable Storage size: %ld bytes\n", pdcs_size);
+ out += sprintf(out, "%ld\n", pdcs_size);
- /* deal with flags */
- if (pdc_stable_read(PDCS_ADDR_PPRI, &devpath, sizeof(devpath)) != PDC_OK)
- return -EIO;
+ return out - buf;
+}
+
+/**
+ * pdcs_auto_read - Stable Storage autoboot/search flag output.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The output buffer to write to.
+ * @knob: The PF_AUTOBOOT or PF_AUTOSEARCH flag
+ */
+static ssize_t
+pdcs_auto_read(struct subsystem *entry, char *buf, int knob)
+{
+ char *out = buf;
+ struct pdcspath_entry *pathentry;
- out += sprintf(out, "Autoboot: %s\n", (devpath.flags & PF_AUTOBOOT) ? "On" : "Off");
- out += sprintf(out, "Autosearch: %s\n", (devpath.flags & PF_AUTOSEARCH) ? "On" : "Off");
- out += sprintf(out, "Timer: %u s\n", (devpath.flags & PF_TIMER) ? (1 << (devpath.flags & PF_TIMER)) : 0);
+ if (!entry || !buf)
+ return -EINVAL;
+
+ /* Current flags are stored in primary boot path entry */
+ pathentry = &pdcspath_entry_primary;
+
+ read_lock(&pathentry->rw_lock);
+ out += sprintf(out, "%s\n", (pathentry->devpath.flags & knob) ?
+ "On" : "Off");
+ read_unlock(&pathentry->rw_lock);
+
+ return out - buf;
+}
+
+/**
+ * pdcs_autoboot_read - Stable Storage autoboot flag output.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The output buffer to write to.
+ */
+static inline ssize_t
+pdcs_autoboot_read(struct subsystem *entry, char *buf)
+{
+ return pdcs_auto_read(entry, buf, PF_AUTOBOOT);
+}
+
+/**
+ * pdcs_autosearch_read - Stable Storage autoboot flag output.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The output buffer to write to.
+ */
+static inline ssize_t
+pdcs_autosearch_read(struct subsystem *entry, char *buf)
+{
+ return pdcs_auto_read(entry, buf, PF_AUTOSEARCH);
+}
+
+/**
+ * pdcs_timer_read - Stable Storage timer count output (in seconds).
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The output buffer to write to.
+ *
+ * The value of the timer field correponds to a number of seconds in powers of 2.
+ */
+static ssize_t
+pdcs_timer_read(struct subsystem *entry, char *buf)
+{
+ char *out = buf;
+ struct pdcspath_entry *pathentry;
+
+ if (!entry || !buf)
+ return -EINVAL;
+
+ /* Current flags are stored in primary boot path entry */
+ pathentry = &pdcspath_entry_primary;
+
+ /* print the timer value in seconds */
+ read_lock(&pathentry->rw_lock);
+ out += sprintf(out, "%u\n", (pathentry->devpath.flags & PF_TIMER) ?
+ (1 << (pathentry->devpath.flags & PF_TIMER)) : 0);
+ read_unlock(&pathentry->rw_lock);
+
+ return out - buf;
+}
+
+/**
+ * pdcs_osid_read - Stable Storage OS ID register output.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The output buffer to write to.
+ */
+static ssize_t
+pdcs_osid_read(struct subsystem *entry, char *buf)
+{
+ char *out = buf;
+ __u32 result;
+ char *tmpstr = NULL;
+
+ if (!entry || !buf)
+ return -EINVAL;
/* get OSID */
if (pdc_stable_read(PDCS_ADDR_OSID, &result, sizeof(result)) != PDC_OK)
@@ -529,13 +630,31 @@ pdcs_info_read(struct subsystem *entry, char *buf)
case 0x0005: tmpstr = "Novell Netware dependent data"; break;
default: tmpstr = "Unknown"; break;
}
- out += sprintf(out, "OS ID: %s (0x%.4x)\n", tmpstr, (result >> 16));
+ out += sprintf(out, "%s (0x%.4x)\n", tmpstr, (result >> 16));
+
+ return out - buf;
+}
+
+/**
+ * pdcs_fastsize_read - Stable Storage FastSize register output.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The output buffer to write to.
+ *
+ * This register holds the amount of system RAM to be tested during boot sequence.
+ */
+static ssize_t
+pdcs_fastsize_read(struct subsystem *entry, char *buf)
+{
+ char *out = buf;
+ __u32 result;
+
+ if (!entry || !buf)
+ return -EINVAL;
/* get fast-size */
if (pdc_stable_read(PDCS_ADDR_FSIZ, &result, sizeof(result)) != PDC_OK)
return -EIO;
- out += sprintf(out, "Memory tested: ");
if ((result & 0x0F) < 0x0E)
out += sprintf(out, "%d kB", (1<<(result & 0x0F))*256);
else
@@ -546,22 +665,18 @@ pdcs_info_read(struct subsystem *entry, char *buf)
}
/**
- * pdcs_info_write - This function handles boot flag modifying.
+ * pdcs_auto_write - This function handles autoboot/search flag modifying.
* @entry: An allocated and populated subsytem struct. We don't use it tho.
* @buf: The input buffer to read from.
* @count: The number of bytes to be read.
+ * @knob: The PF_AUTOBOOT or PF_AUTOSEARCH flag
*
- * We will call this function to change the current boot flags.
+ * We will call this function to change the current autoboot flag.
* We expect a precise syntax:
- * \"n n\" (n == 0 or 1) to toggle respectively AutoBoot and AutoSearch
- *
- * As of now there is no incentive on my side to provide more "knobs" to that
- * interface, since modifying the rest of the data is pretty meaningless when
- * the machine is running and for the expected use of that facility, such as
- * PALO setting up the boot disk when installing a Linux distribution...
+ * \"n\" (n == 0 or 1) to toggle AutoBoot Off or On
*/
static ssize_t
-pdcs_info_write(struct subsystem *entry, const char *buf, size_t count)
+pdcs_auto_write(struct subsystem *entry, const char *buf, size_t count, int knob)
{
struct pdcspath_entry *pathentry;
unsigned char flags;
@@ -582,7 +697,9 @@ pdcs_info_write(struct subsystem *entry, const char *buf, size_t count)
pathentry = &pdcspath_entry_primary;
/* Be nice to the existing flag record */
+ read_lock(&pathentry->rw_lock);
flags = pathentry->devpath.flags;
+ read_unlock(&pathentry->rw_lock);
DPRINTK("%s: flags before: 0x%X\n", __func__, flags);
@@ -595,50 +712,85 @@ pdcs_info_write(struct subsystem *entry, const char *buf, size_t count)
if ((c != 0) && (c != 1))
goto parse_error;
if (c == 0)
- flags &= ~PF_AUTOBOOT;
+ flags &= ~knob;
else
- flags |= PF_AUTOBOOT;
-
- if (*temp++ != ' ')
- goto parse_error;
-
- c = *temp++ - '0';
- if ((c != 0) && (c != 1))
- goto parse_error;
- if (c == 0)
- flags &= ~PF_AUTOSEARCH;
- else
- flags |= PF_AUTOSEARCH;
+ flags |= knob;
DPRINTK("%s: flags after: 0x%X\n", __func__, flags);
/* So far so good, let's get in deep */
+ write_lock(&pathentry->rw_lock);
/* Change the path entry flags first */
pathentry->devpath.flags = flags;
/* Now, dive in. Write back to the hardware */
- WARN_ON(pdcspath_store(pathentry)); /* this warn should *NEVER* happen */
+ pdcspath_store(pathentry);
+ write_unlock(&pathentry->rw_lock);
- printk(KERN_INFO "PDC Stable Storage: changed flags to \"%s\"\n", buf);
+ printk(KERN_INFO PDCS_PREFIX ": changed \"%s\" to \"%s\"\n",
+ (knob & PF_AUTOBOOT) ? "autoboot" : "autosearch",
+ (flags & knob) ? "On" : "Off");
return count;
parse_error:
- printk(KERN_WARNING "%s: Parse error: expect \"n n\" (n == 0 or 1) for AB and AS\n", __func__);
+ printk(KERN_WARNING "%s: Parse error: expect \"n\" (n == 0 or 1)\n", __func__);
return -EINVAL;
}
-/* The last attribute (the 'root' one actually) with all remaining data. */
-static PDCS_ATTR(info, 0600, pdcs_info_read, pdcs_info_write);
+/**
+ * pdcs_autoboot_write - This function handles autoboot flag modifying.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The input buffer to read from.
+ * @count: The number of bytes to be read.
+ *
+ * We will call this function to change the current boot flags.
+ * We expect a precise syntax:
+ * \"n\" (n == 0 or 1) to toggle AutoSearch Off or On
+ */
+static inline ssize_t
+pdcs_autoboot_write(struct subsystem *entry, const char *buf, size_t count)
+{
+ return pdcs_auto_write(entry, buf, count, PF_AUTOBOOT);
+}
+
+/**
+ * pdcs_autosearch_write - This function handles autosearch flag modifying.
+ * @entry: An allocated and populated subsytem struct. We don't use it tho.
+ * @buf: The input buffer to read from.
+ * @count: The number of bytes to be read.
+ *
+ * We will call this function to change the current boot flags.
+ * We expect a precise syntax:
+ * \"n\" (n == 0 or 1) to toggle AutoSearch Off or On
+ */
+static inline ssize_t
+pdcs_autosearch_write(struct subsystem *entry, const char *buf, size_t count)
+{
+ return pdcs_auto_write(entry, buf, count, PF_AUTOSEARCH);
+}
+
+/* The remaining attributes. */
+static PDCS_ATTR(size, 0444, pdcs_size_read, NULL);
+static PDCS_ATTR(autoboot, 0644, pdcs_autoboot_read, pdcs_autoboot_write);
+static PDCS_ATTR(autosearch, 0644, pdcs_autosearch_read, pdcs_autosearch_write);
+static PDCS_ATTR(timer, 0444, pdcs_timer_read, NULL);
+static PDCS_ATTR(osid, 0400, pdcs_osid_read, NULL);
+static PDCS_ATTR(fastsize, 0400, pdcs_fastsize_read, NULL);
static struct subsys_attribute *pdcs_subsys_attrs[] = {
- &pdcs_attr_info,
- NULL, /* maybe more in the future? */
+ &pdcs_attr_size,
+ &pdcs_attr_autoboot,
+ &pdcs_attr_autosearch,
+ &pdcs_attr_timer,
+ &pdcs_attr_osid,
+ &pdcs_attr_fastsize,
+ NULL,
};
static decl_subsys(paths, &ktype_pdcspath, NULL);
-static decl_subsys(pdc, NULL, NULL);
+static decl_subsys(stable, NULL, NULL);
/**
* pdcs_register_pathentries - Prepares path entries kobjects for sysfs usage.
@@ -656,8 +808,16 @@ pdcs_register_pathentries(void)
struct pdcspath_entry *entry;
int err;
+ /* Initialize the entries rw_lock before anything else */
+ for (i = 0; (entry = pdcspath_entries[i]); i++)
+ rwlock_init(&entry->rw_lock);
+
for (i = 0; (entry = pdcspath_entries[i]); i++) {
- if (pdcspath_fetch(entry) < 0)
+ write_lock(&entry->rw_lock);
+ err = pdcspath_fetch(entry);
+ write_unlock(&entry->rw_lock);
+
+ if (err < 0)
continue;
if ((err = kobject_set_name(&entry->kobj, "%s", entry->name)))
@@ -667,13 +827,14 @@ pdcs_register_pathentries(void)
return err;
/* kobject is now registered */
+ write_lock(&entry->rw_lock);
entry->ready = 2;
- if (!entry->dev)
- continue;
-
/* Add a nice symlink to the real device */
- sysfs_create_link(&entry->kobj, &entry->dev->kobj, "device");
+ if (entry->dev)
+ sysfs_create_link(&entry->kobj, &entry->dev->kobj, "device");
+
+ write_unlock(&entry->rw_lock);
}
return 0;
@@ -688,14 +849,17 @@ pdcs_unregister_pathentries(void)
unsigned short i;
struct pdcspath_entry *entry;
- for (i = 0; (entry = pdcspath_entries[i]); i++)
+ for (i = 0; (entry = pdcspath_entries[i]); i++) {
+ read_lock(&entry->rw_lock);
if (entry->ready >= 2)
- kobject_unregister(&entry->kobj);
+ kobject_unregister(&entry->kobj);
+ read_unlock(&entry->rw_lock);
+ }
}
/*
- * For now we register the pdc subsystem with the firmware subsystem
- * and the paths subsystem with the pdc subsystem
+ * For now we register the stable subsystem with the firmware subsystem
+ * and the paths subsystem with the stable subsystem
*/
static int __init
pdc_stable_init(void)
@@ -707,19 +871,23 @@ pdc_stable_init(void)
if (pdc_stable_get_size(&pdcs_size) != PDC_OK)
return -ENODEV;
- printk(KERN_INFO "PDC Stable Storage facility v%s\n", PDCS_VERSION);
+ /* make sure we have enough data */
+ if (pdcs_size < 96)
+ return -ENODATA;
+
+ printk(KERN_INFO PDCS_PREFIX " facility v%s\n", PDCS_VERSION);
- /* For now we'll register the pdc subsys within this driver */
- if ((rc = firmware_register(&pdc_subsys)))
+ /* For now we'll register the stable subsys within this driver */
+ if ((rc = firmware_register(&stable_subsys)))
goto fail_firmreg;
- /* Don't forget the info entry */
+ /* Don't forget the root entries */
for (i = 0; (attr = pdcs_subsys_attrs[i]) && !error; i++)
if (attr->show)
- error = subsys_create_file(&pdc_subsys, attr);
+ error = subsys_create_file(&stable_subsys, attr);
- /* register the paths subsys as a subsystem of pdc subsys */
- kset_set_kset_s(&paths_subsys, pdc_subsys);
+ /* register the paths subsys as a subsystem of stable subsys */
+ kset_set_kset_s(&paths_subsys, stable_subsys);
if ((rc= subsystem_register(&paths_subsys)))
goto fail_subsysreg;
@@ -734,10 +902,10 @@ fail_pdcsreg:
subsystem_unregister(&paths_subsys);
fail_subsysreg:
- firmware_unregister(&pdc_subsys);
+ firmware_unregister(&stable_subsys);
fail_firmreg:
- printk(KERN_INFO "PDC Stable Storage bailing out\n");
+ printk(KERN_INFO PDCS_PREFIX " bailing out\n");
return rc;
}
@@ -747,7 +915,7 @@ pdc_stable_exit(void)
pdcs_unregister_pathentries();
subsystem_unregister(&paths_subsys);
- firmware_unregister(&pdc_subsys);
+ firmware_unregister(&stable_subsys);
}
diff --git a/drivers/parisc/sba_iommu.c b/drivers/parisc/sba_iommu.c
index c85653f315a..52f265e9772 100644
--- a/drivers/parisc/sba_iommu.c
+++ b/drivers/parisc/sba_iommu.c
@@ -2064,14 +2064,13 @@ sba_driver_callback(struct parisc_device *dev)
printk(KERN_INFO "%s found %s at 0x%lx\n",
MODULE_NAME, version, dev->hpa.start);
- sba_dev = kmalloc(sizeof(struct sba_device), GFP_KERNEL);
+ sba_dev = kzalloc(sizeof(struct sba_device), GFP_KERNEL);
if (!sba_dev) {
printk(KERN_ERR MODULE_NAME " - couldn't alloc sba_device\n");
return -ENOMEM;
}
parisc_set_drvdata(dev, sba_dev);
- memset(sba_dev, 0, sizeof(struct sba_device));
for(i=0; i<MAX_IOC; i++)
spin_lock_init(&(sba_dev->ioc[i].res_lock));
diff --git a/drivers/parisc/superio.c b/drivers/parisc/superio.c
index d14888e149b..ba971fecd0d 100644
--- a/drivers/parisc/superio.c
+++ b/drivers/parisc/superio.c
@@ -89,6 +89,9 @@ static struct superio_device sio_dev;
#define DBG_INIT(x...)
#endif
+#define SUPERIO "SuperIO"
+#define PFX SUPERIO ": "
+
static irqreturn_t
superio_interrupt(int parent_irq, void *devp, struct pt_regs *regs)
{
@@ -117,7 +120,7 @@ superio_interrupt(int parent_irq, void *devp, struct pt_regs *regs)
local_irq = results & 0x0f;
if (local_irq == 2 || local_irq > 7) {
- printk(KERN_ERR "SuperIO: slave interrupted!\n");
+ printk(KERN_ERR PFX "slave interrupted!\n");
return IRQ_HANDLED;
}
@@ -128,7 +131,7 @@ superio_interrupt(int parent_irq, void *devp, struct pt_regs *regs)
outb(OCW3_ISR,IC_PIC1+0);
results = inb(IC_PIC1+0);
if ((results & 0x80) == 0) { /* if ISR7 not set: spurious */
- printk(KERN_WARNING "SuperIO: spurious interrupt!\n");
+ printk(KERN_WARNING PFX "spurious interrupt!\n");
return IRQ_HANDLED;
}
}
@@ -163,27 +166,27 @@ superio_init(struct pci_dev *pcidev)
/* ...then properly fixup the USB to point at suckyio PIC */
sio->usb_pdev->irq = superio_fixup_irq(sio->usb_pdev);
- printk(KERN_INFO "SuperIO: Found NS87560 Legacy I/O device at %s (IRQ %i) \n",
+ printk(KERN_INFO PFX "Found NS87560 Legacy I/O device at %s (IRQ %i) \n",
pci_name(pdev), pdev->irq);
pci_read_config_dword (pdev, SIO_SP1BAR, &sio->sp1_base);
sio->sp1_base &= ~1;
- printk (KERN_INFO "SuperIO: Serial port 1 at 0x%x\n", sio->sp1_base);
+ printk(KERN_INFO PFX "Serial port 1 at 0x%x\n", sio->sp1_base);
pci_read_config_dword (pdev, SIO_SP2BAR, &sio->sp2_base);
sio->sp2_base &= ~1;
- printk (KERN_INFO "SuperIO: Serial port 2 at 0x%x\n", sio->sp2_base);
+ printk(KERN_INFO PFX "Serial port 2 at 0x%x\n", sio->sp2_base);
pci_read_config_dword (pdev, SIO_PPBAR, &sio->pp_base);
sio->pp_base &= ~1;
- printk (KERN_INFO "SuperIO: Parallel port at 0x%x\n", sio->pp_base);
+ printk(KERN_INFO PFX "Parallel port at 0x%x\n", sio->pp_base);
pci_read_config_dword (pdev, SIO_FDCBAR, &sio->fdc_base);
sio->fdc_base &= ~1;
- printk (KERN_INFO "SuperIO: Floppy controller at 0x%x\n", sio->fdc_base);
+ printk(KERN_INFO PFX "Floppy controller at 0x%x\n", sio->fdc_base);
pci_read_config_dword (pdev, SIO_ACPIBAR, &sio->acpi_base);
sio->acpi_base &= ~1;
- printk (KERN_INFO "SuperIO: ACPI at 0x%x\n", sio->acpi_base);
+ printk(KERN_INFO PFX "ACPI at 0x%x\n", sio->acpi_base);
request_region (IC_PIC1, 0x1f, "pic1");
request_region (IC_PIC2, 0x1f, "pic2");
@@ -263,14 +266,14 @@ superio_init(struct pci_dev *pcidev)
/* Setup USB power regulation */
outb(1, sio->acpi_base + USB_REG_CR);
if (inb(sio->acpi_base + USB_REG_CR) & 1)
- printk(KERN_INFO "SuperIO: USB regulator enabled\n");
+ printk(KERN_INFO PFX "USB regulator enabled\n");
else
- printk(KERN_ERR "USB regulator not initialized!\n");
+ printk(KERN_ERR PFX "USB regulator not initialized!\n");
if (request_irq(pdev->irq, superio_interrupt, SA_INTERRUPT,
- "SuperIO", (void *)sio)) {
+ SUPERIO, (void *)sio)) {
- printk(KERN_ERR "SuperIO: could not get irq\n");
+ printk(KERN_ERR PFX "could not get irq\n");
BUG();
return;
}
@@ -284,7 +287,7 @@ static void superio_disable_irq(unsigned int irq)
u8 r8;
if ((irq < 1) || (irq == 2) || (irq > 7)) {
- printk(KERN_ERR "SuperIO: Illegal irq number.\n");
+ printk(KERN_ERR PFX "Illegal irq number.\n");
BUG();
return;
}
@@ -301,7 +304,7 @@ static void superio_enable_irq(unsigned int irq)
u8 r8;
if ((irq < 1) || (irq == 2) || (irq > 7)) {
- printk(KERN_ERR "SuperIO: Illegal irq number (%d).\n", irq);
+ printk(KERN_ERR PFX "Illegal irq number (%d).\n", irq);
BUG();
return;
}
@@ -319,7 +322,7 @@ static unsigned int superio_startup_irq(unsigned int irq)
}
static struct hw_interrupt_type superio_interrupt_type = {
- .typename = "SuperIO",
+ .typename = SUPERIO,
.startup = superio_startup_irq,
.shutdown = superio_disable_irq,
.enable = superio_enable_irq,
@@ -413,7 +416,7 @@ static void __devinit superio_serial_init(void)
retval = early_serial_setup(&serial[0]);
if (retval < 0) {
- printk(KERN_WARNING "SuperIO: Register Serial #0 failed.\n");
+ printk(KERN_WARNING PFX "Register Serial #0 failed.\n");
return;
}
@@ -423,7 +426,7 @@ static void __devinit superio_serial_init(void)
retval = early_serial_setup(&serial[1]);
if (retval < 0)
- printk(KERN_WARNING "SuperIO: Register Serial #1 failed.\n");
+ printk(KERN_WARNING PFX "Register Serial #1 failed.\n");
#endif /* CONFIG_SERIAL_8250 */
}
@@ -437,7 +440,7 @@ static void __devinit superio_parport_init(void)
PARPORT_DMA_NONE /* dma */,
NULL /*struct pci_dev* */) )
- printk(KERN_WARNING "SuperIO: Probing parallel port failed.\n");
+ printk(KERN_WARNING PFX "Probing parallel port failed.\n");
#endif /* CONFIG_PARPORT_PC */
}
@@ -499,7 +502,7 @@ static struct pci_device_id superio_tbl[] = {
};
static struct pci_driver superio_driver = {
- .name = "SuperIO",
+ .name = SUPERIO,
.id_table = superio_tbl,
.probe = superio_probe,
};
diff --git a/drivers/parisc/wax.c b/drivers/parisc/wax.c
index 17dce2adf7f..813c2c24ab1 100644
--- a/drivers/parisc/wax.c
+++ b/drivers/parisc/wax.c
@@ -76,7 +76,7 @@ wax_init_chip(struct parisc_device *dev)
struct gsc_irq gsc_irq;
int ret;
- wax = kmalloc(sizeof(*wax), GFP_KERNEL);
+ wax = kzalloc(sizeof(*wax), GFP_KERNEL);
if (!wax)
return -ENOMEM;
diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig
index f605dea5722..f63c387976c 100644
--- a/drivers/parport/Kconfig
+++ b/drivers/parport/Kconfig
@@ -90,6 +90,15 @@ config PARPORT_ARC
depends on ARM && PARPORT
select PARPORT_NOT_PC
+config PARPORT_IP32
+ tristate "SGI IP32 builtin port (EXPERIMENTAL)"
+ depends on SGI_IP32 && PARPORT && EXPERIMENTAL
+ select PARPORT_NOT_PC
+ help
+ Say Y here if you need support for the parallel port on
+ SGI O2 machines. This code is also available as a module (say M),
+ called parport_ip32. If in doubt, saying N is the safe plan.
+
config PARPORT_AMIGA
tristate "Amiga builtin port"
depends on AMIGA && PARPORT
diff --git a/drivers/parport/Makefile b/drivers/parport/Makefile
index 5372212bb9d..a19de35f8de 100644
--- a/drivers/parport/Makefile
+++ b/drivers/parport/Makefile
@@ -17,3 +17,4 @@ obj-$(CONFIG_PARPORT_MFC3) += parport_mfc3.o
obj-$(CONFIG_PARPORT_ATARI) += parport_atari.o
obj-$(CONFIG_PARPORT_SUNBPP) += parport_sunbpp.o
obj-$(CONFIG_PARPORT_GSC) += parport_gsc.o
+obj-$(CONFIG_PARPORT_IP32) += parport_ip32.o
diff --git a/drivers/parport/ieee1284.c b/drivers/parport/ieee1284.c
index 5b887ba5aaf..690b239ad3a 100644
--- a/drivers/parport/ieee1284.c
+++ b/drivers/parport/ieee1284.c
@@ -61,10 +61,10 @@ static void timeout_waiting_on_port (unsigned long cookie)
* set to zero, it returns immediately.
*
* If an interrupt occurs before the timeout period elapses, this
- * function returns one immediately. If it times out, it returns
- * a value greater than zero. An error code less than zero
- * indicates an error (most likely a pending signal), and the
- * calling code should finish what it's doing as soon as it can.
+ * function returns zero immediately. If it times out, it returns
+ * one. An error code less than zero indicates an error (most
+ * likely a pending signal), and the calling code should finish
+ * what it's doing as soon as it can.
*/
int parport_wait_event (struct parport *port, signed long timeout)
@@ -110,7 +110,7 @@ int parport_wait_event (struct parport *port, signed long timeout)
*
* If the status lines take on the desired values before the
* timeout period elapses, parport_poll_peripheral() returns zero
- * immediately. A zero return value greater than zero indicates
+ * immediately. A return value greater than zero indicates
* a timeout. An error code (less than zero) indicates an error,
* most likely a signal that arrived, and the caller should
* finish what it is doing as soon as possible.
diff --git a/drivers/parport/parport_gsc.c b/drivers/parport/parport_gsc.c
index fde29a75f88..1de52d9febf 100644
--- a/drivers/parport/parport_gsc.c
+++ b/drivers/parport/parport_gsc.c
@@ -249,7 +249,7 @@ struct parport *__devinit parport_gsc_probe_port (unsigned long base,
struct parport tmp;
struct parport *p = &tmp;
- priv = kmalloc (sizeof (struct parport_gsc_private), GFP_KERNEL);
+ priv = kzalloc (sizeof (struct parport_gsc_private), GFP_KERNEL);
if (!priv) {
printk (KERN_DEBUG "parport (0x%lx): no memory!\n", base);
return NULL;
diff --git a/drivers/parport/parport_ip32.c b/drivers/parport/parport_ip32.c
new file mode 100644
index 00000000000..46e06e596d7
--- /dev/null
+++ b/drivers/parport/parport_ip32.c
@@ -0,0 +1,2253 @@
+/* Low-level parallel port routines for built-in port on SGI IP32
+ *
+ * Author: Arnaud Giersch <arnaud.giersch@free.fr>
+ *
+ * Based on parport_pc.c by
+ * Phil Blundell, Tim Waugh, Jose Renau, David Campbell,
+ * Andrea Arcangeli, et al.
+ *
+ * Thanks to Ilya A. Volynets-Evenbakh for his help.
+ *
+ * Copyright (C) 2005, 2006 Arnaud Giersch.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/* Current status:
+ *
+ * Basic SPP and PS2 modes are supported.
+ * Support for parallel port IRQ is present.
+ * Hardware SPP (a.k.a. compatibility), EPP, and ECP modes are
+ * supported.
+ * SPP/ECP FIFO can be driven in PIO or DMA mode. PIO mode can work with
+ * or without interrupt support.
+ *
+ * Hardware ECP mode is not fully implemented (ecp_read_data and
+ * ecp_write_addr are actually missing).
+ *
+ * To do:
+ *
+ * Fully implement ECP mode.
+ * EPP and ECP mode need to be tested. I currently do not own any
+ * peripheral supporting these extended mode, and cannot test them.
+ * If DMA mode works well, decide if support for PIO FIFO modes should be
+ * dropped.
+ * Use the io{read,write} family functions when they become available in
+ * the linux-mips.org tree. Note: the MIPS specific functions readsb()
+ * and writesb() are to be translated by ioread8_rep() and iowrite8_rep()
+ * respectively.
+ */
+
+/* The built-in parallel port on the SGI 02 workstation (a.k.a. IP32) is an
+ * IEEE 1284 parallel port driven by a Texas Instrument TL16PIR552PH chip[1].
+ * This chip supports SPP, bidirectional, EPP and ECP modes. It has a 16 byte
+ * FIFO buffer and supports DMA transfers.
+ *
+ * [1] http://focus.ti.com/docs/prod/folders/print/tl16pir552.html
+ *
+ * Theoretically, we could simply use the parport_pc module. It is however
+ * not so simple. The parport_pc code assumes that the parallel port
+ * registers are port-mapped. On the O2, they are memory-mapped.
+ * Furthermore, each register is replicated on 256 consecutive addresses (as
+ * it is for the built-in serial ports on the same chip).
+ */
+
+/*--- Some configuration defines ---------------------------------------*/
+
+/* DEBUG_PARPORT_IP32
+ * 0 disable debug
+ * 1 standard level: pr_debug1 is enabled
+ * 2 parport_ip32_dump_state is enabled
+ * >=3 verbose level: pr_debug is enabled
+ */
+#if !defined(DEBUG_PARPORT_IP32)
+# define DEBUG_PARPORT_IP32 0 /* 0 (disabled) for production */
+#endif
+
+/*----------------------------------------------------------------------*/
+
+/* Setup DEBUG macros. This is done before any includes, just in case we
+ * activate pr_debug() with DEBUG_PARPORT_IP32 >= 3.
+ */
+#if DEBUG_PARPORT_IP32 == 1
+# warning DEBUG_PARPORT_IP32 == 1
+#elif DEBUG_PARPORT_IP32 == 2
+# warning DEBUG_PARPORT_IP32 == 2
+#elif DEBUG_PARPORT_IP32 >= 3
+# warning DEBUG_PARPORT_IP32 >= 3
+# if !defined(DEBUG)
+# define DEBUG /* enable pr_debug() in kernel.h */
+# endif
+#endif
+
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/parport.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/stddef.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/ip32/ip32_ints.h>
+#include <asm/ip32/mace.h>
+
+/*--- Global variables -------------------------------------------------*/
+
+/* Verbose probing on by default for debugging. */
+#if DEBUG_PARPORT_IP32 >= 1
+# define DEFAULT_VERBOSE_PROBING 1
+#else
+# define DEFAULT_VERBOSE_PROBING 0
+#endif
+
+/* Default prefix for printk */
+#define PPIP32 "parport_ip32: "
+
+/*
+ * These are the module parameters:
+ * @features: bit mask of features to enable/disable
+ * (all enabled by default)
+ * @verbose_probing: log chit-chat during initialization
+ */
+#define PARPORT_IP32_ENABLE_IRQ (1U << 0)
+#define PARPORT_IP32_ENABLE_DMA (1U << 1)
+#define PARPORT_IP32_ENABLE_SPP (1U << 2)
+#define PARPORT_IP32_ENABLE_EPP (1U << 3)
+#define PARPORT_IP32_ENABLE_ECP (1U << 4)
+static unsigned int features = ~0U;
+static int verbose_probing = DEFAULT_VERBOSE_PROBING;
+
+/* We do not support more than one port. */
+static struct parport *this_port = NULL;
+
+/* Timing constants for FIFO modes. */
+#define FIFO_NFAULT_TIMEOUT 100 /* milliseconds */
+#define FIFO_POLLING_INTERVAL 50 /* microseconds */
+
+/*--- I/O register definitions -----------------------------------------*/
+
+/**
+ * struct parport_ip32_regs - virtual addresses of parallel port registers
+ * @data: Data Register
+ * @dsr: Device Status Register
+ * @dcr: Device Control Register
+ * @eppAddr: EPP Address Register
+ * @eppData0: EPP Data Register 0
+ * @eppData1: EPP Data Register 1
+ * @eppData2: EPP Data Register 2
+ * @eppData3: EPP Data Register 3
+ * @ecpAFifo: ECP Address FIFO
+ * @fifo: General FIFO register. The same address is used for:
+ * - cFifo, the Parallel Port DATA FIFO
+ * - ecpDFifo, the ECP Data FIFO
+ * - tFifo, the ECP Test FIFO
+ * @cnfgA: Configuration Register A
+ * @cnfgB: Configuration Register B
+ * @ecr: Extended Control Register
+ */
+struct parport_ip32_regs {
+ void __iomem *data;
+ void __iomem *dsr;
+ void __iomem *dcr;
+ void __iomem *eppAddr;
+ void __iomem *eppData0;
+ void __iomem *eppData1;
+ void __iomem *eppData2;
+ void __iomem *eppData3;
+ void __iomem *ecpAFifo;
+ void __iomem *fifo;
+ void __iomem *cnfgA;
+ void __iomem *cnfgB;
+ void __iomem *ecr;
+};
+
+/* Device Status Register */
+#define DSR_nBUSY (1U << 7) /* PARPORT_STATUS_BUSY */
+#define DSR_nACK (1U << 6) /* PARPORT_STATUS_ACK */
+#define DSR_PERROR (1U << 5) /* PARPORT_STATUS_PAPEROUT */
+#define DSR_SELECT (1U << 4) /* PARPORT_STATUS_SELECT */
+#define DSR_nFAULT (1U << 3) /* PARPORT_STATUS_ERROR */
+#define DSR_nPRINT (1U << 2) /* specific to TL16PIR552 */
+/* #define DSR_reserved (1U << 1) */
+#define DSR_TIMEOUT (1U << 0) /* EPP timeout */
+
+/* Device Control Register */
+/* #define DCR_reserved (1U << 7) | (1U << 6) */
+#define DCR_DIR (1U << 5) /* direction */
+#define DCR_IRQ (1U << 4) /* interrupt on nAck */
+#define DCR_SELECT (1U << 3) /* PARPORT_CONTROL_SELECT */
+#define DCR_nINIT (1U << 2) /* PARPORT_CONTROL_INIT */
+#define DCR_AUTOFD (1U << 1) /* PARPORT_CONTROL_AUTOFD */
+#define DCR_STROBE (1U << 0) /* PARPORT_CONTROL_STROBE */
+
+/* ECP Configuration Register A */
+#define CNFGA_IRQ (1U << 7)
+#define CNFGA_ID_MASK ((1U << 6) | (1U << 5) | (1U << 4))
+#define CNFGA_ID_SHIFT 4
+#define CNFGA_ID_16 (00U << CNFGA_ID_SHIFT)
+#define CNFGA_ID_8 (01U << CNFGA_ID_SHIFT)
+#define CNFGA_ID_32 (02U << CNFGA_ID_SHIFT)
+/* #define CNFGA_reserved (1U << 3) */
+#define CNFGA_nBYTEINTRANS (1U << 2)
+#define CNFGA_PWORDLEFT ((1U << 1) | (1U << 0))
+
+/* ECP Configuration Register B */
+#define CNFGB_COMPRESS (1U << 7)
+#define CNFGB_INTRVAL (1U << 6)
+#define CNFGB_IRQ_MASK ((1U << 5) | (1U << 4) | (1U << 3))
+#define CNFGB_IRQ_SHIFT 3
+#define CNFGB_DMA_MASK ((1U << 2) | (1U << 1) | (1U << 0))
+#define CNFGB_DMA_SHIFT 0
+
+/* Extended Control Register */
+#define ECR_MODE_MASK ((1U << 7) | (1U << 6) | (1U << 5))
+#define ECR_MODE_SHIFT 5
+#define ECR_MODE_SPP (00U << ECR_MODE_SHIFT)
+#define ECR_MODE_PS2 (01U << ECR_MODE_SHIFT)
+#define ECR_MODE_PPF (02U << ECR_MODE_SHIFT)
+#define ECR_MODE_ECP (03U << ECR_MODE_SHIFT)
+#define ECR_MODE_EPP (04U << ECR_MODE_SHIFT)
+/* #define ECR_MODE_reserved (05U << ECR_MODE_SHIFT) */
+#define ECR_MODE_TST (06U << ECR_MODE_SHIFT)
+#define ECR_MODE_CFG (07U << ECR_MODE_SHIFT)
+#define ECR_nERRINTR (1U << 4)
+#define ECR_DMAEN (1U << 3)
+#define ECR_SERVINTR (1U << 2)
+#define ECR_F_FULL (1U << 1)
+#define ECR_F_EMPTY (1U << 0)
+
+/*--- Private data -----------------------------------------------------*/
+
+/**
+ * enum parport_ip32_irq_mode - operation mode of interrupt handler
+ * @PARPORT_IP32_IRQ_FWD: forward interrupt to the upper parport layer
+ * @PARPORT_IP32_IRQ_HERE: interrupt is handled locally
+ */
+enum parport_ip32_irq_mode { PARPORT_IP32_IRQ_FWD, PARPORT_IP32_IRQ_HERE };
+
+/**
+ * struct parport_ip32_private - private stuff for &struct parport
+ * @regs: register addresses
+ * @dcr_cache: cached contents of DCR
+ * @dcr_writable: bit mask of writable DCR bits
+ * @pword: number of bytes per PWord
+ * @fifo_depth: number of PWords that FIFO will hold
+ * @readIntrThreshold: minimum number of PWords we can read
+ * if we get an interrupt
+ * @writeIntrThreshold: minimum number of PWords we can write
+ * if we get an interrupt
+ * @irq_mode: operation mode of interrupt handler for this port
+ * @irq_complete: mutex used to wait for an interrupt to occur
+ */
+struct parport_ip32_private {
+ struct parport_ip32_regs regs;
+ unsigned int dcr_cache;
+ unsigned int dcr_writable;
+ unsigned int pword;
+ unsigned int fifo_depth;
+ unsigned int readIntrThreshold;
+ unsigned int writeIntrThreshold;
+ enum parport_ip32_irq_mode irq_mode;
+ struct completion irq_complete;
+};
+
+/*--- Debug code -------------------------------------------------------*/
+
+/*
+ * pr_debug1 - print debug messages
+ *
+ * This is like pr_debug(), but is defined for %DEBUG_PARPORT_IP32 >= 1
+ */
+#if DEBUG_PARPORT_IP32 >= 1
+# define pr_debug1(...) printk(KERN_DEBUG __VA_ARGS__)
+#else /* DEBUG_PARPORT_IP32 < 1 */
+# define pr_debug1(...) do { } while (0)
+#endif
+
+/*
+ * pr_trace, pr_trace1 - trace function calls
+ * @p: pointer to &struct parport
+ * @fmt: printk format string
+ * @...: parameters for format string
+ *
+ * Macros used to trace function calls. The given string is formatted after
+ * function name. pr_trace() uses pr_debug(), and pr_trace1() uses
+ * pr_debug1(). __pr_trace() is the low-level macro and is not to be used
+ * directly.
+ */
+#define __pr_trace(pr, p, fmt, ...) \
+ pr("%s: %s" fmt "\n", \
+ ({ const struct parport *__p = (p); \
+ __p ? __p->name : "parport_ip32"; }), \
+ __func__ , ##__VA_ARGS__)
+#define pr_trace(p, fmt, ...) __pr_trace(pr_debug, p, fmt , ##__VA_ARGS__)
+#define pr_trace1(p, fmt, ...) __pr_trace(pr_debug1, p, fmt , ##__VA_ARGS__)
+
+/*
+ * __pr_probe, pr_probe - print message if @verbose_probing is true
+ * @p: pointer to &struct parport
+ * @fmt: printk format string
+ * @...: parameters for format string
+ *
+ * For new lines, use pr_probe(). Use __pr_probe() for continued lines.
+ */
+#define __pr_probe(...) \
+ do { if (verbose_probing) printk(__VA_ARGS__); } while (0)
+#define pr_probe(p, fmt, ...) \
+ __pr_probe(KERN_INFO PPIP32 "0x%lx: " fmt, (p)->base , ##__VA_ARGS__)
+
+/*
+ * parport_ip32_dump_state - print register status of parport
+ * @p: pointer to &struct parport
+ * @str: string to add in message
+ * @show_ecp_config: shall we dump ECP configuration registers too?
+ *
+ * This function is only here for debugging purpose, and should be used with
+ * care. Reading the parallel port registers may have undesired side effects.
+ * Especially if @show_ecp_config is true, the parallel port is resetted.
+ * This function is only defined if %DEBUG_PARPORT_IP32 >= 2.
+ */
+#if DEBUG_PARPORT_IP32 >= 2
+static void parport_ip32_dump_state(struct parport *p, char *str,
+ unsigned int show_ecp_config)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ unsigned int i;
+
+ printk(KERN_DEBUG PPIP32 "%s: state (%s):\n", p->name, str);
+ {
+ static const char ecr_modes[8][4] = {"SPP", "PS2", "PPF",
+ "ECP", "EPP", "???",
+ "TST", "CFG"};
+ unsigned int ecr = readb(priv->regs.ecr);
+ printk(KERN_DEBUG PPIP32 " ecr=0x%02x", ecr);
+ printk(" %s",
+ ecr_modes[(ecr & ECR_MODE_MASK) >> ECR_MODE_SHIFT]);
+ if (ecr & ECR_nERRINTR)
+ printk(",nErrIntrEn");
+ if (ecr & ECR_DMAEN)
+ printk(",dmaEn");
+ if (ecr & ECR_SERVINTR)
+ printk(",serviceIntr");
+ if (ecr & ECR_F_FULL)
+ printk(",f_full");
+ if (ecr & ECR_F_EMPTY)
+ printk(",f_empty");
+ printk("\n");
+ }
+ if (show_ecp_config) {
+ unsigned int oecr, cnfgA, cnfgB;
+ oecr = readb(priv->regs.ecr);
+ writeb(ECR_MODE_PS2, priv->regs.ecr);
+ writeb(ECR_MODE_CFG, priv->regs.ecr);
+ cnfgA = readb(priv->regs.cnfgA);
+ cnfgB = readb(priv->regs.cnfgB);
+ writeb(ECR_MODE_PS2, priv->regs.ecr);
+ writeb(oecr, priv->regs.ecr);
+ printk(KERN_DEBUG PPIP32 " cnfgA=0x%02x", cnfgA);
+ printk(" ISA-%s", (cnfgA & CNFGA_IRQ) ? "Level" : "Pulses");
+ switch (cnfgA & CNFGA_ID_MASK) {
+ case CNFGA_ID_8:
+ printk(",8 bits");
+ break;
+ case CNFGA_ID_16:
+ printk(",16 bits");
+ break;
+ case CNFGA_ID_32:
+ printk(",32 bits");
+ break;
+ default:
+ printk(",unknown ID");
+ break;
+ }
+ if (!(cnfgA & CNFGA_nBYTEINTRANS))
+ printk(",ByteInTrans");
+ if ((cnfgA & CNFGA_ID_MASK) != CNFGA_ID_8)
+ printk(",%d byte%s left", cnfgA & CNFGA_PWORDLEFT,
+ ((cnfgA & CNFGA_PWORDLEFT) > 1) ? "s" : "");
+ printk("\n");
+ printk(KERN_DEBUG PPIP32 " cnfgB=0x%02x", cnfgB);
+ printk(" irq=%u,dma=%u",
+ (cnfgB & CNFGB_IRQ_MASK) >> CNFGB_IRQ_SHIFT,
+ (cnfgB & CNFGB_DMA_MASK) >> CNFGB_DMA_SHIFT);
+ printk(",intrValue=%d", !!(cnfgB & CNFGB_INTRVAL));
+ if (cnfgB & CNFGB_COMPRESS)
+ printk(",compress");
+ printk("\n");
+ }
+ for (i = 0; i < 2; i++) {
+ unsigned int dcr = i ? priv->dcr_cache : readb(priv->regs.dcr);
+ printk(KERN_DEBUG PPIP32 " dcr(%s)=0x%02x",
+ i ? "soft" : "hard", dcr);
+ printk(" %s", (dcr & DCR_DIR) ? "rev" : "fwd");
+ if (dcr & DCR_IRQ)
+ printk(",ackIntEn");
+ if (!(dcr & DCR_SELECT))
+ printk(",nSelectIn");
+ if (dcr & DCR_nINIT)
+ printk(",nInit");
+ if (!(dcr & DCR_AUTOFD))
+ printk(",nAutoFD");
+ if (!(dcr & DCR_STROBE))
+ printk(",nStrobe");
+ printk("\n");
+ }
+#define sep (f++ ? ',' : ' ')
+ {
+ unsigned int f = 0;
+ unsigned int dsr = readb(priv->regs.dsr);
+ printk(KERN_DEBUG PPIP32 " dsr=0x%02x", dsr);
+ if (!(dsr & DSR_nBUSY))
+ printk("%cBusy", sep);
+ if (dsr & DSR_nACK)
+ printk("%cnAck", sep);
+ if (dsr & DSR_PERROR)
+ printk("%cPError", sep);
+ if (dsr & DSR_SELECT)
+ printk("%cSelect", sep);
+ if (dsr & DSR_nFAULT)
+ printk("%cnFault", sep);
+ if (!(dsr & DSR_nPRINT))
+ printk("%c(Print)", sep);
+ if (dsr & DSR_TIMEOUT)
+ printk("%cTimeout", sep);
+ printk("\n");
+ }
+#undef sep
+}
+#else /* DEBUG_PARPORT_IP32 < 2 */
+#define parport_ip32_dump_state(...) do { } while (0)
+#endif
+
+/*
+ * CHECK_EXTRA_BITS - track and log extra bits
+ * @p: pointer to &struct parport
+ * @b: byte to inspect
+ * @m: bit mask of authorized bits
+ *
+ * This is used to track and log extra bits that should not be there in
+ * parport_ip32_write_control() and parport_ip32_frob_control(). It is only
+ * defined if %DEBUG_PARPORT_IP32 >= 1.
+ */
+#if DEBUG_PARPORT_IP32 >= 1
+#define CHECK_EXTRA_BITS(p, b, m) \
+ do { \
+ unsigned int __b = (b), __m = (m); \
+ if (__b & ~__m) \
+ pr_debug1(PPIP32 "%s: extra bits in %s(%s): " \
+ "0x%02x/0x%02x\n", \
+ (p)->name, __func__, #b, __b, __m); \
+ } while (0)
+#else /* DEBUG_PARPORT_IP32 < 1 */
+#define CHECK_EXTRA_BITS(...) do { } while (0)
+#endif
+
+/*--- IP32 parallel port DMA operations --------------------------------*/
+
+/**
+ * struct parport_ip32_dma_data - private data needed for DMA operation
+ * @dir: DMA direction (from or to device)
+ * @buf: buffer physical address
+ * @len: buffer length
+ * @next: address of next bytes to DMA transfer
+ * @left: number of bytes remaining
+ * @ctx: next context to write (0: context_a; 1: context_b)
+ * @irq_on: are the DMA IRQs currently enabled?
+ * @lock: spinlock to protect access to the structure
+ */
+struct parport_ip32_dma_data {
+ enum dma_data_direction dir;
+ dma_addr_t buf;
+ dma_addr_t next;
+ size_t len;
+ size_t left;
+ unsigned int ctx;
+ unsigned int irq_on;
+ spinlock_t lock;
+};
+static struct parport_ip32_dma_data parport_ip32_dma;
+
+/**
+ * parport_ip32_dma_setup_context - setup next DMA context
+ * @limit: maximum data size for the context
+ *
+ * The alignment constraints must be verified in caller function, and the
+ * parameter @limit must be set accordingly.
+ */
+static void parport_ip32_dma_setup_context(unsigned int limit)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&parport_ip32_dma.lock, flags);
+ if (parport_ip32_dma.left > 0) {
+ /* Note: ctxreg is "volatile" here only because
+ * mace->perif.ctrl.parport.context_a and context_b are
+ * "volatile". */
+ volatile u64 __iomem *ctxreg = (parport_ip32_dma.ctx == 0) ?
+ &mace->perif.ctrl.parport.context_a :
+ &mace->perif.ctrl.parport.context_b;
+ u64 count;
+ u64 ctxval;
+ if (parport_ip32_dma.left <= limit) {
+ count = parport_ip32_dma.left;
+ ctxval = MACEPAR_CONTEXT_LASTFLAG;
+ } else {
+ count = limit;
+ ctxval = 0;
+ }
+
+ pr_trace(NULL,
+ "(%u): 0x%04x:0x%04x, %u -> %u%s",
+ limit,
+ (unsigned int)parport_ip32_dma.buf,
+ (unsigned int)parport_ip32_dma.next,
+ (unsigned int)count,
+ parport_ip32_dma.ctx, ctxval ? "*" : "");
+
+ ctxval |= parport_ip32_dma.next &
+ MACEPAR_CONTEXT_BASEADDR_MASK;
+ ctxval |= ((count - 1) << MACEPAR_CONTEXT_DATALEN_SHIFT) &
+ MACEPAR_CONTEXT_DATALEN_MASK;
+ writeq(ctxval, ctxreg);
+ parport_ip32_dma.next += count;
+ parport_ip32_dma.left -= count;
+ parport_ip32_dma.ctx ^= 1U;
+ }
+ /* If there is nothing more to send, disable IRQs to avoid to
+ * face an IRQ storm which can lock the machine. Disable them
+ * only once. */
+ if (parport_ip32_dma.left == 0 && parport_ip32_dma.irq_on) {
+ pr_debug(PPIP32 "IRQ off (ctx)\n");
+ disable_irq_nosync(MACEISA_PAR_CTXA_IRQ);
+ disable_irq_nosync(MACEISA_PAR_CTXB_IRQ);
+ parport_ip32_dma.irq_on = 0;
+ }
+ spin_unlock_irqrestore(&parport_ip32_dma.lock, flags);
+}
+
+/**
+ * parport_ip32_dma_interrupt - DMA interrupt handler
+ * @irq: interrupt number
+ * @dev_id: unused
+ * @regs: pointer to &struct pt_regs
+ */
+static irqreturn_t parport_ip32_dma_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ if (parport_ip32_dma.left)
+ pr_trace(NULL, "(%d): ctx=%d", irq, parport_ip32_dma.ctx);
+ parport_ip32_dma_setup_context(MACEPAR_CONTEXT_DATA_BOUND);
+ return IRQ_HANDLED;
+}
+
+#if DEBUG_PARPORT_IP32
+static irqreturn_t parport_ip32_merr_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ pr_trace1(NULL, "(%d)", irq);
+ return IRQ_HANDLED;
+}
+#endif
+
+/**
+ * parport_ip32_dma_start - begins a DMA transfer
+ * @dir: DMA direction: DMA_TO_DEVICE or DMA_FROM_DEVICE
+ * @addr: pointer to data buffer
+ * @count: buffer size
+ *
+ * Calls to parport_ip32_dma_start() and parport_ip32_dma_stop() must be
+ * correctly balanced.
+ */
+static int parport_ip32_dma_start(enum dma_data_direction dir,
+ void *addr, size_t count)
+{
+ unsigned int limit;
+ u64 ctrl;
+
+ pr_trace(NULL, "(%d, %lu)", dir, (unsigned long)count);
+
+ /* FIXME - add support for DMA_FROM_DEVICE. In this case, buffer must
+ * be 64 bytes aligned. */
+ BUG_ON(dir != DMA_TO_DEVICE);
+
+ /* Reset DMA controller */
+ ctrl = MACEPAR_CTLSTAT_RESET;
+ writeq(ctrl, &mace->perif.ctrl.parport.cntlstat);
+
+ /* DMA IRQs should normally be enabled */
+ if (!parport_ip32_dma.irq_on) {
+ WARN_ON(1);
+ enable_irq(MACEISA_PAR_CTXA_IRQ);
+ enable_irq(MACEISA_PAR_CTXB_IRQ);
+ parport_ip32_dma.irq_on = 1;
+ }
+
+ /* Prepare DMA pointers */
+ parport_ip32_dma.dir = dir;
+ parport_ip32_dma.buf = dma_map_single(NULL, addr, count, dir);
+ parport_ip32_dma.len = count;
+ parport_ip32_dma.next = parport_ip32_dma.buf;
+ parport_ip32_dma.left = parport_ip32_dma.len;
+ parport_ip32_dma.ctx = 0;
+
+ /* Setup DMA direction and first two contexts */
+ ctrl = (dir == DMA_TO_DEVICE) ? 0 : MACEPAR_CTLSTAT_DIRECTION;
+ writeq(ctrl, &mace->perif.ctrl.parport.cntlstat);
+ /* Single transfer should not cross a 4K page boundary */
+ limit = MACEPAR_CONTEXT_DATA_BOUND -
+ (parport_ip32_dma.next & (MACEPAR_CONTEXT_DATA_BOUND - 1));
+ parport_ip32_dma_setup_context(limit);
+ parport_ip32_dma_setup_context(MACEPAR_CONTEXT_DATA_BOUND);
+
+ /* Real start of DMA transfer */
+ ctrl |= MACEPAR_CTLSTAT_ENABLE;
+ writeq(ctrl, &mace->perif.ctrl.parport.cntlstat);
+
+ return 0;
+}
+
+/**
+ * parport_ip32_dma_stop - ends a running DMA transfer
+ *
+ * Calls to parport_ip32_dma_start() and parport_ip32_dma_stop() must be
+ * correctly balanced.
+ */
+static void parport_ip32_dma_stop(void)
+{
+ u64 ctx_a;
+ u64 ctx_b;
+ u64 ctrl;
+ u64 diag;
+ size_t res[2]; /* {[0] = res_a, [1] = res_b} */
+
+ pr_trace(NULL, "()");
+
+ /* Disable IRQs */
+ spin_lock_irq(&parport_ip32_dma.lock);
+ if (parport_ip32_dma.irq_on) {
+ pr_debug(PPIP32 "IRQ off (stop)\n");
+ disable_irq_nosync(MACEISA_PAR_CTXA_IRQ);
+ disable_irq_nosync(MACEISA_PAR_CTXB_IRQ);
+ parport_ip32_dma.irq_on = 0;
+ }
+ spin_unlock_irq(&parport_ip32_dma.lock);
+ /* Force IRQ synchronization, even if the IRQs were disabled
+ * elsewhere. */
+ synchronize_irq(MACEISA_PAR_CTXA_IRQ);
+ synchronize_irq(MACEISA_PAR_CTXB_IRQ);
+
+ /* Stop DMA transfer */
+ ctrl = readq(&mace->perif.ctrl.parport.cntlstat);
+ ctrl &= ~MACEPAR_CTLSTAT_ENABLE;
+ writeq(ctrl, &mace->perif.ctrl.parport.cntlstat);
+
+ /* Adjust residue (parport_ip32_dma.left) */
+ ctx_a = readq(&mace->perif.ctrl.parport.context_a);
+ ctx_b = readq(&mace->perif.ctrl.parport.context_b);
+ ctrl = readq(&mace->perif.ctrl.parport.cntlstat);
+ diag = readq(&mace->perif.ctrl.parport.diagnostic);
+ res[0] = (ctrl & MACEPAR_CTLSTAT_CTXA_VALID) ?
+ 1 + ((ctx_a & MACEPAR_CONTEXT_DATALEN_MASK) >>
+ MACEPAR_CONTEXT_DATALEN_SHIFT) :
+ 0;
+ res[1] = (ctrl & MACEPAR_CTLSTAT_CTXB_VALID) ?
+ 1 + ((ctx_b & MACEPAR_CONTEXT_DATALEN_MASK) >>
+ MACEPAR_CONTEXT_DATALEN_SHIFT) :
+ 0;
+ if (diag & MACEPAR_DIAG_DMACTIVE)
+ res[(diag & MACEPAR_DIAG_CTXINUSE) != 0] =
+ 1 + ((diag & MACEPAR_DIAG_CTRMASK) >>
+ MACEPAR_DIAG_CTRSHIFT);
+ parport_ip32_dma.left += res[0] + res[1];
+
+ /* Reset DMA controller, and re-enable IRQs */
+ ctrl = MACEPAR_CTLSTAT_RESET;
+ writeq(ctrl, &mace->perif.ctrl.parport.cntlstat);
+ pr_debug(PPIP32 "IRQ on (stop)\n");
+ enable_irq(MACEISA_PAR_CTXA_IRQ);
+ enable_irq(MACEISA_PAR_CTXB_IRQ);
+ parport_ip32_dma.irq_on = 1;
+
+ dma_unmap_single(NULL, parport_ip32_dma.buf, parport_ip32_dma.len,
+ parport_ip32_dma.dir);
+}
+
+/**
+ * parport_ip32_dma_get_residue - get residue from last DMA transfer
+ *
+ * Returns the number of bytes remaining from last DMA transfer.
+ */
+static inline size_t parport_ip32_dma_get_residue(void)
+{
+ return parport_ip32_dma.left;
+}
+
+/**
+ * parport_ip32_dma_register - initialize DMA engine
+ *
+ * Returns zero for success.
+ */
+static int parport_ip32_dma_register(void)
+{
+ int err;
+
+ spin_lock_init(&parport_ip32_dma.lock);
+ parport_ip32_dma.irq_on = 1;
+
+ /* Reset DMA controller */
+ writeq(MACEPAR_CTLSTAT_RESET, &mace->perif.ctrl.parport.cntlstat);
+
+ /* Request IRQs */
+ err = request_irq(MACEISA_PAR_CTXA_IRQ, parport_ip32_dma_interrupt,
+ 0, "parport_ip32", NULL);
+ if (err)
+ goto fail_a;
+ err = request_irq(MACEISA_PAR_CTXB_IRQ, parport_ip32_dma_interrupt,
+ 0, "parport_ip32", NULL);
+ if (err)
+ goto fail_b;
+#if DEBUG_PARPORT_IP32
+ /* FIXME - what is this IRQ for? */
+ err = request_irq(MACEISA_PAR_MERR_IRQ, parport_ip32_merr_interrupt,
+ 0, "parport_ip32", NULL);
+ if (err)
+ goto fail_merr;
+#endif
+ return 0;
+
+#if DEBUG_PARPORT_IP32
+fail_merr:
+ free_irq(MACEISA_PAR_CTXB_IRQ, NULL);
+#endif
+fail_b:
+ free_irq(MACEISA_PAR_CTXA_IRQ, NULL);
+fail_a:
+ return err;
+}
+
+/**
+ * parport_ip32_dma_unregister - release and free resources for DMA engine
+ */
+static void parport_ip32_dma_unregister(void)
+{
+#if DEBUG_PARPORT_IP32
+ free_irq(MACEISA_PAR_MERR_IRQ, NULL);
+#endif
+ free_irq(MACEISA_PAR_CTXB_IRQ, NULL);
+ free_irq(MACEISA_PAR_CTXA_IRQ, NULL);
+}
+
+/*--- Interrupt handlers and associates --------------------------------*/
+
+/**
+ * parport_ip32_wakeup - wakes up code waiting for an interrupt
+ * @p: pointer to &struct parport
+ */
+static inline void parport_ip32_wakeup(struct parport *p)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ complete(&priv->irq_complete);
+}
+
+/**
+ * parport_ip32_interrupt - interrupt handler
+ * @irq: interrupt number
+ * @dev_id: pointer to &struct parport
+ * @regs: pointer to &struct pt_regs
+ *
+ * Caught interrupts are forwarded to the upper parport layer if IRQ_mode is
+ * %PARPORT_IP32_IRQ_FWD.
+ */
+static irqreturn_t parport_ip32_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs)
+{
+ struct parport * const p = dev_id;
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ enum parport_ip32_irq_mode irq_mode = priv->irq_mode;
+ switch (irq_mode) {
+ case PARPORT_IP32_IRQ_FWD:
+ parport_generic_irq(irq, p, regs);
+ break;
+ case PARPORT_IP32_IRQ_HERE:
+ parport_ip32_wakeup(p);
+ break;
+ }
+ return IRQ_HANDLED;
+}
+
+/*--- Some utility function to manipulate ECR register -----------------*/
+
+/**
+ * parport_ip32_read_econtrol - read contents of the ECR register
+ * @p: pointer to &struct parport
+ */
+static inline unsigned int parport_ip32_read_econtrol(struct parport *p)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ return readb(priv->regs.ecr);
+}
+
+/**
+ * parport_ip32_write_econtrol - write new contents to the ECR register
+ * @p: pointer to &struct parport
+ * @c: new value to write
+ */
+static inline void parport_ip32_write_econtrol(struct parport *p,
+ unsigned int c)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ writeb(c, priv->regs.ecr);
+}
+
+/**
+ * parport_ip32_frob_econtrol - change bits from the ECR register
+ * @p: pointer to &struct parport
+ * @mask: bit mask of bits to change
+ * @val: new value for changed bits
+ *
+ * Read from the ECR, mask out the bits in @mask, exclusive-or with the bits
+ * in @val, and write the result to the ECR.
+ */
+static inline void parport_ip32_frob_econtrol(struct parport *p,
+ unsigned int mask,
+ unsigned int val)
+{
+ unsigned int c;
+ c = (parport_ip32_read_econtrol(p) & ~mask) ^ val;
+ parport_ip32_write_econtrol(p, c);
+}
+
+/**
+ * parport_ip32_set_mode - change mode of ECP port
+ * @p: pointer to &struct parport
+ * @mode: new mode to write in ECR
+ *
+ * ECR is reset in a sane state (interrupts and DMA disabled), and placed in
+ * mode @mode. Go through PS2 mode if needed.
+ */
+static void parport_ip32_set_mode(struct parport *p, unsigned int mode)
+{
+ unsigned int omode;
+
+ mode &= ECR_MODE_MASK;
+ omode = parport_ip32_read_econtrol(p) & ECR_MODE_MASK;
+
+ if (!(mode == ECR_MODE_SPP || mode == ECR_MODE_PS2
+ || omode == ECR_MODE_SPP || omode == ECR_MODE_PS2)) {
+ /* We have to go through PS2 mode */
+ unsigned int ecr = ECR_MODE_PS2 | ECR_nERRINTR | ECR_SERVINTR;
+ parport_ip32_write_econtrol(p, ecr);
+ }
+ parport_ip32_write_econtrol(p, mode | ECR_nERRINTR | ECR_SERVINTR);
+}
+
+/*--- Basic functions needed for parport -------------------------------*/
+
+/**
+ * parport_ip32_read_data - return current contents of the DATA register
+ * @p: pointer to &struct parport
+ */
+static inline unsigned char parport_ip32_read_data(struct parport *p)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ return readb(priv->regs.data);
+}
+
+/**
+ * parport_ip32_write_data - set new contents for the DATA register
+ * @p: pointer to &struct parport
+ * @d: new value to write
+ */
+static inline void parport_ip32_write_data(struct parport *p, unsigned char d)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ writeb(d, priv->regs.data);
+}
+
+/**
+ * parport_ip32_read_status - return current contents of the DSR register
+ * @p: pointer to &struct parport
+ */
+static inline unsigned char parport_ip32_read_status(struct parport *p)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ return readb(priv->regs.dsr);
+}
+
+/**
+ * __parport_ip32_read_control - return cached contents of the DCR register
+ * @p: pointer to &struct parport
+ */
+static inline unsigned int __parport_ip32_read_control(struct parport *p)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ return priv->dcr_cache; /* use soft copy */
+}
+
+/**
+ * __parport_ip32_write_control - set new contents for the DCR register
+ * @p: pointer to &struct parport
+ * @c: new value to write
+ */
+static inline void __parport_ip32_write_control(struct parport *p,
+ unsigned int c)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ CHECK_EXTRA_BITS(p, c, priv->dcr_writable);
+ c &= priv->dcr_writable; /* only writable bits */
+ writeb(c, priv->regs.dcr);
+ priv->dcr_cache = c; /* update soft copy */
+}
+
+/**
+ * __parport_ip32_frob_control - change bits from the DCR register
+ * @p: pointer to &struct parport
+ * @mask: bit mask of bits to change
+ * @val: new value for changed bits
+ *
+ * This is equivalent to read from the DCR, mask out the bits in @mask,
+ * exclusive-or with the bits in @val, and write the result to the DCR.
+ * Actually, the cached contents of the DCR is used.
+ */
+static inline void __parport_ip32_frob_control(struct parport *p,
+ unsigned int mask,
+ unsigned int val)
+{
+ unsigned int c;
+ c = (__parport_ip32_read_control(p) & ~mask) ^ val;
+ __parport_ip32_write_control(p, c);
+}
+
+/**
+ * parport_ip32_read_control - return cached contents of the DCR register
+ * @p: pointer to &struct parport
+ *
+ * The return value is masked so as to only return the value of %DCR_STROBE,
+ * %DCR_AUTOFD, %DCR_nINIT, and %DCR_SELECT.
+ */
+static inline unsigned char parport_ip32_read_control(struct parport *p)
+{
+ const unsigned int rm =
+ DCR_STROBE | DCR_AUTOFD | DCR_nINIT | DCR_SELECT;
+ return __parport_ip32_read_control(p) & rm;
+}
+
+/**
+ * parport_ip32_write_control - set new contents for the DCR register
+ * @p: pointer to &struct parport
+ * @c: new value to write
+ *
+ * The value is masked so as to only change the value of %DCR_STROBE,
+ * %DCR_AUTOFD, %DCR_nINIT, and %DCR_SELECT.
+ */
+static inline void parport_ip32_write_control(struct parport *p,
+ unsigned char c)
+{
+ const unsigned int wm =
+ DCR_STROBE | DCR_AUTOFD | DCR_nINIT | DCR_SELECT;
+ CHECK_EXTRA_BITS(p, c, wm);
+ __parport_ip32_frob_control(p, wm, c & wm);
+}
+
+/**
+ * parport_ip32_frob_control - change bits from the DCR register
+ * @p: pointer to &struct parport
+ * @mask: bit mask of bits to change
+ * @val: new value for changed bits
+ *
+ * This differs from __parport_ip32_frob_control() in that it only allows to
+ * change the value of %DCR_STROBE, %DCR_AUTOFD, %DCR_nINIT, and %DCR_SELECT.
+ */
+static inline unsigned char parport_ip32_frob_control(struct parport *p,
+ unsigned char mask,
+ unsigned char val)
+{
+ const unsigned int wm =
+ DCR_STROBE | DCR_AUTOFD | DCR_nINIT | DCR_SELECT;
+ CHECK_EXTRA_BITS(p, mask, wm);
+ CHECK_EXTRA_BITS(p, val, wm);
+ __parport_ip32_frob_control(p, mask & wm, val & wm);
+ return parport_ip32_read_control(p);
+}
+
+/**
+ * parport_ip32_disable_irq - disable interrupts on the rising edge of nACK
+ * @p: pointer to &struct parport
+ */
+static inline void parport_ip32_disable_irq(struct parport *p)
+{
+ __parport_ip32_frob_control(p, DCR_IRQ, 0);
+}
+
+/**
+ * parport_ip32_enable_irq - enable interrupts on the rising edge of nACK
+ * @p: pointer to &struct parport
+ */
+static inline void parport_ip32_enable_irq(struct parport *p)
+{
+ __parport_ip32_frob_control(p, DCR_IRQ, DCR_IRQ);
+}
+
+/**
+ * parport_ip32_data_forward - enable host-to-peripheral communications
+ * @p: pointer to &struct parport
+ *
+ * Enable the data line drivers, for 8-bit host-to-peripheral communications.
+ */
+static inline void parport_ip32_data_forward(struct parport *p)
+{
+ __parport_ip32_frob_control(p, DCR_DIR, 0);
+}
+
+/**
+ * parport_ip32_data_reverse - enable peripheral-to-host communications
+ * @p: pointer to &struct parport
+ *
+ * Place the data bus in a high impedance state, if @p->modes has the
+ * PARPORT_MODE_TRISTATE bit set.
+ */
+static inline void parport_ip32_data_reverse(struct parport *p)
+{
+ __parport_ip32_frob_control(p, DCR_DIR, DCR_DIR);
+}
+
+/**
+ * parport_ip32_init_state - for core parport code
+ * @dev: pointer to &struct pardevice
+ * @s: pointer to &struct parport_state to initialize
+ */
+static void parport_ip32_init_state(struct pardevice *dev,
+ struct parport_state *s)
+{
+ s->u.ip32.dcr = DCR_SELECT | DCR_nINIT;
+ s->u.ip32.ecr = ECR_MODE_PS2 | ECR_nERRINTR | ECR_SERVINTR;
+}
+
+/**
+ * parport_ip32_save_state - for core parport code
+ * @p: pointer to &struct parport
+ * @s: pointer to &struct parport_state to save state to
+ */
+static void parport_ip32_save_state(struct parport *p,
+ struct parport_state *s)
+{
+ s->u.ip32.dcr = __parport_ip32_read_control(p);
+ s->u.ip32.ecr = parport_ip32_read_econtrol(p);
+}
+
+/**
+ * parport_ip32_restore_state - for core parport code
+ * @p: pointer to &struct parport
+ * @s: pointer to &struct parport_state to restore state from
+ */
+static void parport_ip32_restore_state(struct parport *p,
+ struct parport_state *s)
+{
+ parport_ip32_set_mode(p, s->u.ip32.ecr & ECR_MODE_MASK);
+ parport_ip32_write_econtrol(p, s->u.ip32.ecr);
+ __parport_ip32_write_control(p, s->u.ip32.dcr);
+}
+
+/*--- EPP mode functions -----------------------------------------------*/
+
+/**
+ * parport_ip32_clear_epp_timeout - clear Timeout bit in EPP mode
+ * @p: pointer to &struct parport
+ *
+ * Returns 1 if the Timeout bit is clear, and 0 otherwise.
+ */
+static unsigned int parport_ip32_clear_epp_timeout(struct parport *p)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ unsigned int cleared;
+
+ if (!(parport_ip32_read_status(p) & DSR_TIMEOUT))
+ cleared = 1;
+ else {
+ unsigned int r;
+ /* To clear timeout some chips require double read */
+ parport_ip32_read_status(p);
+ r = parport_ip32_read_status(p);
+ /* Some reset by writing 1 */
+ writeb(r | DSR_TIMEOUT, priv->regs.dsr);
+ /* Others by writing 0 */
+ writeb(r & ~DSR_TIMEOUT, priv->regs.dsr);
+
+ r = parport_ip32_read_status(p);
+ cleared = !(r & DSR_TIMEOUT);
+ }
+
+ pr_trace(p, "(): %s", cleared ? "cleared" : "failed");
+ return cleared;
+}
+
+/**
+ * parport_ip32_epp_read - generic EPP read function
+ * @eppreg: I/O register to read from
+ * @p: pointer to &struct parport
+ * @buf: buffer to store read data
+ * @len: length of buffer @buf
+ * @flags: may be PARPORT_EPP_FAST
+ */
+static size_t parport_ip32_epp_read(void __iomem *eppreg,
+ struct parport *p, void *buf,
+ size_t len, int flags)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ size_t got;
+ parport_ip32_set_mode(p, ECR_MODE_EPP);
+ parport_ip32_data_reverse(p);
+ parport_ip32_write_control(p, DCR_nINIT);
+ if ((flags & PARPORT_EPP_FAST) && (len > 1)) {
+ readsb(eppreg, buf, len);
+ if (readb(priv->regs.dsr) & DSR_TIMEOUT) {
+ parport_ip32_clear_epp_timeout(p);
+ return -EIO;
+ }
+ got = len;
+ } else {
+ u8 *bufp = buf;
+ for (got = 0; got < len; got++) {
+ *bufp++ = readb(eppreg);
+ if (readb(priv->regs.dsr) & DSR_TIMEOUT) {
+ parport_ip32_clear_epp_timeout(p);
+ break;
+ }
+ }
+ }
+ parport_ip32_data_forward(p);
+ parport_ip32_set_mode(p, ECR_MODE_PS2);
+ return got;
+}
+
+/**
+ * parport_ip32_epp_write - generic EPP write function
+ * @eppreg: I/O register to write to
+ * @p: pointer to &struct parport
+ * @buf: buffer of data to write
+ * @len: length of buffer @buf
+ * @flags: may be PARPORT_EPP_FAST
+ */
+static size_t parport_ip32_epp_write(void __iomem *eppreg,
+ struct parport *p, const void *buf,
+ size_t len, int flags)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ size_t written;
+ parport_ip32_set_mode(p, ECR_MODE_EPP);
+ parport_ip32_data_forward(p);
+ parport_ip32_write_control(p, DCR_nINIT);
+ if ((flags & PARPORT_EPP_FAST) && (len > 1)) {
+ writesb(eppreg, buf, len);
+ if (readb(priv->regs.dsr) & DSR_TIMEOUT) {
+ parport_ip32_clear_epp_timeout(p);
+ return -EIO;
+ }
+ written = len;
+ } else {
+ const u8 *bufp = buf;
+ for (written = 0; written < len; written++) {
+ writeb(*bufp++, eppreg);
+ if (readb(priv->regs.dsr) & DSR_TIMEOUT) {
+ parport_ip32_clear_epp_timeout(p);
+ break;
+ }
+ }
+ }
+ parport_ip32_set_mode(p, ECR_MODE_PS2);
+ return written;
+}
+
+/**
+ * parport_ip32_epp_read_data - read a block of data in EPP mode
+ * @p: pointer to &struct parport
+ * @buf: buffer to store read data
+ * @len: length of buffer @buf
+ * @flags: may be PARPORT_EPP_FAST
+ */
+static size_t parport_ip32_epp_read_data(struct parport *p, void *buf,
+ size_t len, int flags)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ return parport_ip32_epp_read(priv->regs.eppData0, p, buf, len, flags);
+}
+
+/**
+ * parport_ip32_epp_write_data - write a block of data in EPP mode
+ * @p: pointer to &struct parport
+ * @buf: buffer of data to write
+ * @len: length of buffer @buf
+ * @flags: may be PARPORT_EPP_FAST
+ */
+static size_t parport_ip32_epp_write_data(struct parport *p, const void *buf,
+ size_t len, int flags)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ return parport_ip32_epp_write(priv->regs.eppData0, p, buf, len, flags);
+}
+
+/**
+ * parport_ip32_epp_read_addr - read a block of addresses in EPP mode
+ * @p: pointer to &struct parport
+ * @buf: buffer to store read data
+ * @len: length of buffer @buf
+ * @flags: may be PARPORT_EPP_FAST
+ */
+static size_t parport_ip32_epp_read_addr(struct parport *p, void *buf,
+ size_t len, int flags)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ return parport_ip32_epp_read(priv->regs.eppAddr, p, buf, len, flags);
+}
+
+/**
+ * parport_ip32_epp_write_addr - write a block of addresses in EPP mode
+ * @p: pointer to &struct parport
+ * @buf: buffer of data to write
+ * @len: length of buffer @buf
+ * @flags: may be PARPORT_EPP_FAST
+ */
+static size_t parport_ip32_epp_write_addr(struct parport *p, const void *buf,
+ size_t len, int flags)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ return parport_ip32_epp_write(priv->regs.eppAddr, p, buf, len, flags);
+}
+
+/*--- ECP mode functions (FIFO) ----------------------------------------*/
+
+/**
+ * parport_ip32_fifo_wait_break - check if the waiting function should return
+ * @p: pointer to &struct parport
+ * @expire: timeout expiring date, in jiffies
+ *
+ * parport_ip32_fifo_wait_break() checks if the waiting function should return
+ * immediately or not. The break conditions are:
+ * - expired timeout;
+ * - a pending signal;
+ * - nFault asserted low.
+ * This function also calls cond_resched().
+ */
+static unsigned int parport_ip32_fifo_wait_break(struct parport *p,
+ unsigned long expire)
+{
+ cond_resched();
+ if (time_after(jiffies, expire)) {
+ pr_debug1(PPIP32 "%s: FIFO write timed out\n", p->name);
+ return 1;
+ }
+ if (signal_pending(current)) {
+ pr_debug1(PPIP32 "%s: Signal pending\n", p->name);
+ return 1;
+ }
+ if (!(parport_ip32_read_status(p) & DSR_nFAULT)) {
+ pr_debug1(PPIP32 "%s: nFault asserted low\n", p->name);
+ return 1;
+ }
+ return 0;
+}
+
+/**
+ * parport_ip32_fwp_wait_polling - wait for FIFO to empty (polling)
+ * @p: pointer to &struct parport
+ *
+ * Returns the number of bytes that can safely be written in the FIFO. A
+ * return value of zero means that the calling function should terminate as
+ * fast as possible.
+ */
+static unsigned int parport_ip32_fwp_wait_polling(struct parport *p)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ struct parport * const physport = p->physport;
+ unsigned long expire;
+ unsigned int count;
+ unsigned int ecr;
+
+ expire = jiffies + physport->cad->timeout;
+ count = 0;
+ while (1) {
+ if (parport_ip32_fifo_wait_break(p, expire))
+ break;
+
+ /* Check FIFO state. We do nothing when the FIFO is nor full,
+ * nor empty. It appears that the FIFO full bit is not always
+ * reliable, the FIFO state is sometimes wrongly reported, and
+ * the chip gets confused if we give it another byte. */
+ ecr = parport_ip32_read_econtrol(p);
+ if (ecr & ECR_F_EMPTY) {
+ /* FIFO is empty, fill it up */
+ count = priv->fifo_depth;
+ break;
+ }
+
+ /* Wait a moment... */
+ udelay(FIFO_POLLING_INTERVAL);
+ } /* while (1) */
+
+ return count;
+}
+
+/**
+ * parport_ip32_fwp_wait_interrupt - wait for FIFO to empty (interrupt-driven)
+ * @p: pointer to &struct parport
+ *
+ * Returns the number of bytes that can safely be written in the FIFO. A
+ * return value of zero means that the calling function should terminate as
+ * fast as possible.
+ */
+static unsigned int parport_ip32_fwp_wait_interrupt(struct parport *p)
+{
+ static unsigned int lost_interrupt = 0;
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ struct parport * const physport = p->physport;
+ unsigned long nfault_timeout;
+ unsigned long expire;
+ unsigned int count;
+ unsigned int ecr;
+
+ nfault_timeout = min((unsigned long)physport->cad->timeout,
+ msecs_to_jiffies(FIFO_NFAULT_TIMEOUT));
+ expire = jiffies + physport->cad->timeout;
+ count = 0;
+ while (1) {
+ if (parport_ip32_fifo_wait_break(p, expire))
+ break;
+
+ /* Initialize mutex used to take interrupts into account */
+ INIT_COMPLETION(priv->irq_complete);
+
+ /* Enable serviceIntr */
+ parport_ip32_frob_econtrol(p, ECR_SERVINTR, 0);
+
+ /* Enabling serviceIntr while the FIFO is empty does not
+ * always generate an interrupt, so check for emptiness
+ * now. */
+ ecr = parport_ip32_read_econtrol(p);
+ if (!(ecr & ECR_F_EMPTY)) {
+ /* FIFO is not empty: wait for an interrupt or a
+ * timeout to occur */
+ wait_for_completion_interruptible_timeout(
+ &priv->irq_complete, nfault_timeout);
+ ecr = parport_ip32_read_econtrol(p);
+ if ((ecr & ECR_F_EMPTY) && !(ecr & ECR_SERVINTR)
+ && !lost_interrupt) {
+ printk(KERN_WARNING PPIP32
+ "%s: lost interrupt in %s\n",
+ p->name, __func__);
+ lost_interrupt = 1;
+ }
+ }
+
+ /* Disable serviceIntr */
+ parport_ip32_frob_econtrol(p, ECR_SERVINTR, ECR_SERVINTR);
+
+ /* Check FIFO state */
+ if (ecr & ECR_F_EMPTY) {
+ /* FIFO is empty, fill it up */
+ count = priv->fifo_depth;
+ break;
+ } else if (ecr & ECR_SERVINTR) {
+ /* FIFO is not empty, but we know that can safely push
+ * writeIntrThreshold bytes into it */
+ count = priv->writeIntrThreshold;
+ break;
+ }
+ /* FIFO is not empty, and we did not get any interrupt.
+ * Either it's time to check for nFault, or a signal is
+ * pending. This is verified in
+ * parport_ip32_fifo_wait_break(), so we continue the loop. */
+ } /* while (1) */
+
+ return count;
+}
+
+/**
+ * parport_ip32_fifo_write_block_pio - write a block of data (PIO mode)
+ * @p: pointer to &struct parport
+ * @buf: buffer of data to write
+ * @len: length of buffer @buf
+ *
+ * Uses PIO to write the contents of the buffer @buf into the parallel port
+ * FIFO. Returns the number of bytes that were actually written. It can work
+ * with or without the help of interrupts. The parallel port must be
+ * correctly initialized before calling parport_ip32_fifo_write_block_pio().
+ */
+static size_t parport_ip32_fifo_write_block_pio(struct parport *p,
+ const void *buf, size_t len)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ const u8 *bufp = buf;
+ size_t left = len;
+
+ priv->irq_mode = PARPORT_IP32_IRQ_HERE;
+
+ while (left > 0) {
+ unsigned int count;
+
+ count = (p->irq == PARPORT_IRQ_NONE) ?
+ parport_ip32_fwp_wait_polling(p) :
+ parport_ip32_fwp_wait_interrupt(p);
+ if (count == 0)
+ break; /* Transmission should be stopped */
+ if (count > left)
+ count = left;
+ if (count == 1) {
+ writeb(*bufp, priv->regs.fifo);
+ bufp++, left--;
+ } else {
+ writesb(priv->regs.fifo, bufp, count);
+ bufp += count, left -= count;
+ }
+ }
+
+ priv->irq_mode = PARPORT_IP32_IRQ_FWD;
+
+ return len - left;
+}
+
+/**
+ * parport_ip32_fifo_write_block_dma - write a block of data (DMA mode)
+ * @p: pointer to &struct parport
+ * @buf: buffer of data to write
+ * @len: length of buffer @buf
+ *
+ * Uses DMA to write the contents of the buffer @buf into the parallel port
+ * FIFO. Returns the number of bytes that were actually written. The
+ * parallel port must be correctly initialized before calling
+ * parport_ip32_fifo_write_block_dma().
+ */
+static size_t parport_ip32_fifo_write_block_dma(struct parport *p,
+ const void *buf, size_t len)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ struct parport * const physport = p->physport;
+ unsigned long nfault_timeout;
+ unsigned long expire;
+ size_t written;
+ unsigned int ecr;
+
+ priv->irq_mode = PARPORT_IP32_IRQ_HERE;
+
+ parport_ip32_dma_start(DMA_TO_DEVICE, (void *)buf, len);
+ INIT_COMPLETION(priv->irq_complete);
+ parport_ip32_frob_econtrol(p, ECR_DMAEN | ECR_SERVINTR, ECR_DMAEN);
+
+ nfault_timeout = min((unsigned long)physport->cad->timeout,
+ msecs_to_jiffies(FIFO_NFAULT_TIMEOUT));
+ expire = jiffies + physport->cad->timeout;
+ while (1) {
+ if (parport_ip32_fifo_wait_break(p, expire))
+ break;
+ wait_for_completion_interruptible_timeout(&priv->irq_complete,
+ nfault_timeout);
+ ecr = parport_ip32_read_econtrol(p);
+ if (ecr & ECR_SERVINTR)
+ break; /* DMA transfer just finished */
+ }
+ parport_ip32_dma_stop();
+ written = len - parport_ip32_dma_get_residue();
+
+ priv->irq_mode = PARPORT_IP32_IRQ_FWD;
+
+ return written;
+}
+
+/**
+ * parport_ip32_fifo_write_block - write a block of data
+ * @p: pointer to &struct parport
+ * @buf: buffer of data to write
+ * @len: length of buffer @buf
+ *
+ * Uses PIO or DMA to write the contents of the buffer @buf into the parallel
+ * p FIFO. Returns the number of bytes that were actually written.
+ */
+static size_t parport_ip32_fifo_write_block(struct parport *p,
+ const void *buf, size_t len)
+{
+ size_t written = 0;
+ if (len)
+ /* FIXME - Maybe some threshold value should be set for @len
+ * under which we revert to PIO mode? */
+ written = (p->modes & PARPORT_MODE_DMA) ?
+ parport_ip32_fifo_write_block_dma(p, buf, len) :
+ parport_ip32_fifo_write_block_pio(p, buf, len);
+ return written;
+}
+
+/**
+ * parport_ip32_drain_fifo - wait for FIFO to empty
+ * @p: pointer to &struct parport
+ * @timeout: timeout, in jiffies
+ *
+ * This function waits for FIFO to empty. It returns 1 when FIFO is empty, or
+ * 0 if the timeout @timeout is reached before, or if a signal is pending.
+ */
+static unsigned int parport_ip32_drain_fifo(struct parport *p,
+ unsigned long timeout)
+{
+ unsigned long expire = jiffies + timeout;
+ unsigned int polling_interval;
+ unsigned int counter;
+
+ /* Busy wait for approx. 200us */
+ for (counter = 0; counter < 40; counter++) {
+ if (parport_ip32_read_econtrol(p) & ECR_F_EMPTY)
+ break;
+ if (time_after(jiffies, expire))
+ break;
+ if (signal_pending(current))
+ break;
+ udelay(5);
+ }
+ /* Poll slowly. Polling interval starts with 1 millisecond, and is
+ * increased exponentially until 128. */
+ polling_interval = 1; /* msecs */
+ while (!(parport_ip32_read_econtrol(p) & ECR_F_EMPTY)) {
+ if (time_after_eq(jiffies, expire))
+ break;
+ msleep_interruptible(polling_interval);
+ if (signal_pending(current))
+ break;
+ if (polling_interval < 128)
+ polling_interval *= 2;
+ }
+
+ return !!(parport_ip32_read_econtrol(p) & ECR_F_EMPTY);
+}
+
+/**
+ * parport_ip32_get_fifo_residue - reset FIFO
+ * @p: pointer to &struct parport
+ * @mode: current operation mode (ECR_MODE_PPF or ECR_MODE_ECP)
+ *
+ * This function resets FIFO, and returns the number of bytes remaining in it.
+ */
+static unsigned int parport_ip32_get_fifo_residue(struct parport *p,
+ unsigned int mode)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ unsigned int residue;
+ unsigned int cnfga;
+
+ /* FIXME - We are missing one byte if the printer is off-line. I
+ * don't know how to detect this. It looks that the full bit is not
+ * always reliable. For the moment, the problem is avoided in most
+ * cases by testing for BUSY in parport_ip32_compat_write_data().
+ */
+ if (parport_ip32_read_econtrol(p) & ECR_F_EMPTY)
+ residue = 0;
+ else {
+ pr_debug1(PPIP32 "%s: FIFO is stuck\n", p->name);
+
+ /* Stop all transfers.
+ *
+ * Microsoft's document instructs to drive DCR_STROBE to 0,
+ * but it doesn't work (at least in Compatibility mode, not
+ * tested in ECP mode). Switching directly to Test mode (as
+ * in parport_pc) is not an option: it does confuse the port,
+ * ECP service interrupts are no more working after that. A
+ * hard reset is then needed to revert to a sane state.
+ *
+ * Let's hope that the FIFO is really stuck and that the
+ * peripheral doesn't wake up now.
+ */
+ parport_ip32_frob_control(p, DCR_STROBE, 0);
+
+ /* Fill up FIFO */
+ for (residue = priv->fifo_depth; residue > 0; residue--) {
+ if (parport_ip32_read_econtrol(p) & ECR_F_FULL)
+ break;
+ writeb(0x00, priv->regs.fifo);
+ }
+ }
+ if (residue)
+ pr_debug1(PPIP32 "%s: %d PWord%s left in FIFO\n",
+ p->name, residue,
+ (residue == 1) ? " was" : "s were");
+
+ /* Now reset the FIFO */
+ parport_ip32_set_mode(p, ECR_MODE_PS2);
+
+ /* Host recovery for ECP mode */
+ if (mode == ECR_MODE_ECP) {
+ parport_ip32_data_reverse(p);
+ parport_ip32_frob_control(p, DCR_nINIT, 0);
+ if (parport_wait_peripheral(p, DSR_PERROR, 0))
+ pr_debug1(PPIP32 "%s: PEerror timeout 1 in %s\n",
+ p->name, __func__);
+ parport_ip32_frob_control(p, DCR_STROBE, DCR_STROBE);
+ parport_ip32_frob_control(p, DCR_nINIT, DCR_nINIT);
+ if (parport_wait_peripheral(p, DSR_PERROR, DSR_PERROR))
+ pr_debug1(PPIP32 "%s: PEerror timeout 2 in %s\n",
+ p->name, __func__);
+ }
+
+ /* Adjust residue if needed */
+ parport_ip32_set_mode(p, ECR_MODE_CFG);
+ cnfga = readb(priv->regs.cnfgA);
+ if (!(cnfga & CNFGA_nBYTEINTRANS)) {
+ pr_debug1(PPIP32 "%s: cnfgA contains 0x%02x\n",
+ p->name, cnfga);
+ pr_debug1(PPIP32 "%s: Accounting for extra byte\n",
+ p->name);
+ residue++;
+ }
+
+ /* Don't care about partial PWords since we do not support
+ * PWord != 1 byte. */
+
+ /* Back to forward PS2 mode. */
+ parport_ip32_set_mode(p, ECR_MODE_PS2);
+ parport_ip32_data_forward(p);
+
+ return residue;
+}
+
+/**
+ * parport_ip32_compat_write_data - write a block of data in SPP mode
+ * @p: pointer to &struct parport
+ * @buf: buffer of data to write
+ * @len: length of buffer @buf
+ * @flags: ignored
+ */
+static size_t parport_ip32_compat_write_data(struct parport *p,
+ const void *buf, size_t len,
+ int flags)
+{
+ static unsigned int ready_before = 1;
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ struct parport * const physport = p->physport;
+ size_t written = 0;
+
+ /* Special case: a timeout of zero means we cannot call schedule().
+ * Also if O_NONBLOCK is set then use the default implementation. */
+ if (physport->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK)
+ return parport_ieee1284_write_compat(p, buf, len, flags);
+
+ /* Reset FIFO, go in forward mode, and disable ackIntEn */
+ parport_ip32_set_mode(p, ECR_MODE_PS2);
+ parport_ip32_write_control(p, DCR_SELECT | DCR_nINIT);
+ parport_ip32_data_forward(p);
+ parport_ip32_disable_irq(p);
+ parport_ip32_set_mode(p, ECR_MODE_PPF);
+ physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+
+ /* Wait for peripheral to become ready */
+ if (parport_wait_peripheral(p, DSR_nBUSY | DSR_nFAULT,
+ DSR_nBUSY | DSR_nFAULT)) {
+ /* Avoid to flood the logs */
+ if (ready_before)
+ printk(KERN_INFO PPIP32 "%s: not ready in %s\n",
+ p->name, __func__);
+ ready_before = 0;
+ goto stop;
+ }
+ ready_before = 1;
+
+ written = parport_ip32_fifo_write_block(p, buf, len);
+
+ /* Wait FIFO to empty. Timeout is proportional to FIFO_depth. */
+ parport_ip32_drain_fifo(p, physport->cad->timeout * priv->fifo_depth);
+
+ /* Check for a potential residue */
+ written -= parport_ip32_get_fifo_residue(p, ECR_MODE_PPF);
+
+ /* Then, wait for BUSY to get low. */
+ if (parport_wait_peripheral(p, DSR_nBUSY, DSR_nBUSY))
+ printk(KERN_DEBUG PPIP32 "%s: BUSY timeout in %s\n",
+ p->name, __func__);
+
+stop:
+ /* Reset FIFO */
+ parport_ip32_set_mode(p, ECR_MODE_PS2);
+ physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+ return written;
+}
+
+/*
+ * FIXME - Insert here parport_ip32_ecp_read_data().
+ */
+
+/**
+ * parport_ip32_ecp_write_data - write a block of data in ECP mode
+ * @p: pointer to &struct parport
+ * @buf: buffer of data to write
+ * @len: length of buffer @buf
+ * @flags: ignored
+ */
+static size_t parport_ip32_ecp_write_data(struct parport *p,
+ const void *buf, size_t len,
+ int flags)
+{
+ static unsigned int ready_before = 1;
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ struct parport * const physport = p->physport;
+ size_t written = 0;
+
+ /* Special case: a timeout of zero means we cannot call schedule().
+ * Also if O_NONBLOCK is set then use the default implementation. */
+ if (physport->cad->timeout <= PARPORT_INACTIVITY_O_NONBLOCK)
+ return parport_ieee1284_ecp_write_data(p, buf, len, flags);
+
+ /* Negotiate to forward mode if necessary. */
+ if (physport->ieee1284.phase != IEEE1284_PH_FWD_IDLE) {
+ /* Event 47: Set nInit high. */
+ parport_ip32_frob_control(p, DCR_nINIT | DCR_AUTOFD,
+ DCR_nINIT | DCR_AUTOFD);
+
+ /* Event 49: PError goes high. */
+ if (parport_wait_peripheral(p, DSR_PERROR, DSR_PERROR)) {
+ printk(KERN_DEBUG PPIP32 "%s: PError timeout in %s",
+ p->name, __func__);
+ physport->ieee1284.phase = IEEE1284_PH_ECP_DIR_UNKNOWN;
+ return 0;
+ }
+ }
+
+ /* Reset FIFO, go in forward mode, and disable ackIntEn */
+ parport_ip32_set_mode(p, ECR_MODE_PS2);
+ parport_ip32_write_control(p, DCR_SELECT | DCR_nINIT);
+ parport_ip32_data_forward(p);
+ parport_ip32_disable_irq(p);
+ parport_ip32_set_mode(p, ECR_MODE_ECP);
+ physport->ieee1284.phase = IEEE1284_PH_FWD_DATA;
+
+ /* Wait for peripheral to become ready */
+ if (parport_wait_peripheral(p, DSR_nBUSY | DSR_nFAULT,
+ DSR_nBUSY | DSR_nFAULT)) {
+ /* Avoid to flood the logs */
+ if (ready_before)
+ printk(KERN_INFO PPIP32 "%s: not ready in %s\n",
+ p->name, __func__);
+ ready_before = 0;
+ goto stop;
+ }
+ ready_before = 1;
+
+ written = parport_ip32_fifo_write_block(p, buf, len);
+
+ /* Wait FIFO to empty. Timeout is proportional to FIFO_depth. */
+ parport_ip32_drain_fifo(p, physport->cad->timeout * priv->fifo_depth);
+
+ /* Check for a potential residue */
+ written -= parport_ip32_get_fifo_residue(p, ECR_MODE_ECP);
+
+ /* Then, wait for BUSY to get low. */
+ if (parport_wait_peripheral(p, DSR_nBUSY, DSR_nBUSY))
+ printk(KERN_DEBUG PPIP32 "%s: BUSY timeout in %s\n",
+ p->name, __func__);
+
+stop:
+ /* Reset FIFO */
+ parport_ip32_set_mode(p, ECR_MODE_PS2);
+ physport->ieee1284.phase = IEEE1284_PH_FWD_IDLE;
+
+ return written;
+}
+
+/*
+ * FIXME - Insert here parport_ip32_ecp_write_addr().
+ */
+
+/*--- Default parport operations ---------------------------------------*/
+
+static __initdata struct parport_operations parport_ip32_ops = {
+ .write_data = parport_ip32_write_data,
+ .read_data = parport_ip32_read_data,
+
+ .write_control = parport_ip32_write_control,
+ .read_control = parport_ip32_read_control,
+ .frob_control = parport_ip32_frob_control,
+
+ .read_status = parport_ip32_read_status,
+
+ .enable_irq = parport_ip32_enable_irq,
+ .disable_irq = parport_ip32_disable_irq,
+
+ .data_forward = parport_ip32_data_forward,
+ .data_reverse = parport_ip32_data_reverse,
+
+ .init_state = parport_ip32_init_state,
+ .save_state = parport_ip32_save_state,
+ .restore_state = parport_ip32_restore_state,
+
+ .epp_write_data = parport_ieee1284_epp_write_data,
+ .epp_read_data = parport_ieee1284_epp_read_data,
+ .epp_write_addr = parport_ieee1284_epp_write_addr,
+ .epp_read_addr = parport_ieee1284_epp_read_addr,
+
+ .ecp_write_data = parport_ieee1284_ecp_write_data,
+ .ecp_read_data = parport_ieee1284_ecp_read_data,
+ .ecp_write_addr = parport_ieee1284_ecp_write_addr,
+
+ .compat_write_data = parport_ieee1284_write_compat,
+ .nibble_read_data = parport_ieee1284_read_nibble,
+ .byte_read_data = parport_ieee1284_read_byte,
+
+ .owner = THIS_MODULE,
+};
+
+/*--- Device detection -------------------------------------------------*/
+
+/**
+ * parport_ip32_ecp_supported - check for an ECP port
+ * @p: pointer to the &parport structure
+ *
+ * Returns 1 if an ECP port is found, and 0 otherwise. This function actually
+ * checks if an Extended Control Register seems to be present. On successful
+ * return, the port is placed in SPP mode.
+ */
+static __init unsigned int parport_ip32_ecp_supported(struct parport *p)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ unsigned int ecr;
+
+ ecr = ECR_MODE_PS2 | ECR_nERRINTR | ECR_SERVINTR;
+ writeb(ecr, priv->regs.ecr);
+ if (readb(priv->regs.ecr) != (ecr | ECR_F_EMPTY))
+ goto fail;
+
+ pr_probe(p, "Found working ECR register\n");
+ parport_ip32_set_mode(p, ECR_MODE_SPP);
+ parport_ip32_write_control(p, DCR_SELECT | DCR_nINIT);
+ return 1;
+
+fail:
+ pr_probe(p, "ECR register not found\n");
+ return 0;
+}
+
+/**
+ * parport_ip32_fifo_supported - check for FIFO parameters
+ * @p: pointer to the &parport structure
+ *
+ * Check for FIFO parameters of an Extended Capabilities Port. Returns 1 on
+ * success, and 0 otherwise. Adjust FIFO parameters in the parport structure.
+ * On return, the port is placed in SPP mode.
+ */
+static __init unsigned int parport_ip32_fifo_supported(struct parport *p)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ unsigned int configa, configb;
+ unsigned int pword;
+ unsigned int i;
+
+ /* Configuration mode */
+ parport_ip32_set_mode(p, ECR_MODE_CFG);
+ configa = readb(priv->regs.cnfgA);
+ configb = readb(priv->regs.cnfgB);
+
+ /* Find out PWord size */
+ switch (configa & CNFGA_ID_MASK) {
+ case CNFGA_ID_8:
+ pword = 1;
+ break;
+ case CNFGA_ID_16:
+ pword = 2;
+ break;
+ case CNFGA_ID_32:
+ pword = 4;
+ break;
+ default:
+ pr_probe(p, "Unknown implementation ID: 0x%0x\n",
+ (configa & CNFGA_ID_MASK) >> CNFGA_ID_SHIFT);
+ goto fail;
+ break;
+ }
+ if (pword != 1) {
+ pr_probe(p, "Unsupported PWord size: %u\n", pword);
+ goto fail;
+ }
+ priv->pword = pword;
+ pr_probe(p, "PWord is %u bits\n", 8 * priv->pword);
+
+ /* Check for compression support */
+ writeb(configb | CNFGB_COMPRESS, priv->regs.cnfgB);
+ if (readb(priv->regs.cnfgB) & CNFGB_COMPRESS)
+ pr_probe(p, "Hardware compression detected (unsupported)\n");
+ writeb(configb & ~CNFGB_COMPRESS, priv->regs.cnfgB);
+
+ /* Reset FIFO and go in test mode (no interrupt, no DMA) */
+ parport_ip32_set_mode(p, ECR_MODE_TST);
+
+ /* FIFO must be empty now */
+ if (!(readb(priv->regs.ecr) & ECR_F_EMPTY)) {
+ pr_probe(p, "FIFO not reset\n");
+ goto fail;
+ }
+
+ /* Find out FIFO depth. */
+ priv->fifo_depth = 0;
+ for (i = 0; i < 1024; i++) {
+ if (readb(priv->regs.ecr) & ECR_F_FULL) {
+ /* FIFO full */
+ priv->fifo_depth = i;
+ break;
+ }
+ writeb((u8)i, priv->regs.fifo);
+ }
+ if (i >= 1024) {
+ pr_probe(p, "Can't fill FIFO\n");
+ goto fail;
+ }
+ if (!priv->fifo_depth) {
+ pr_probe(p, "Can't get FIFO depth\n");
+ goto fail;
+ }
+ pr_probe(p, "FIFO is %u PWords deep\n", priv->fifo_depth);
+
+ /* Enable interrupts */
+ parport_ip32_frob_econtrol(p, ECR_SERVINTR, 0);
+
+ /* Find out writeIntrThreshold: number of PWords we know we can write
+ * if we get an interrupt. */
+ priv->writeIntrThreshold = 0;
+ for (i = 0; i < priv->fifo_depth; i++) {
+ if (readb(priv->regs.fifo) != (u8)i) {
+ pr_probe(p, "Invalid data in FIFO\n");
+ goto fail;
+ }
+ if (!priv->writeIntrThreshold
+ && readb(priv->regs.ecr) & ECR_SERVINTR)
+ /* writeIntrThreshold reached */
+ priv->writeIntrThreshold = i + 1;
+ if (i + 1 < priv->fifo_depth
+ && readb(priv->regs.ecr) & ECR_F_EMPTY) {
+ /* FIFO empty before the last byte? */
+ pr_probe(p, "Data lost in FIFO\n");
+ goto fail;
+ }
+ }
+ if (!priv->writeIntrThreshold) {
+ pr_probe(p, "Can't get writeIntrThreshold\n");
+ goto fail;
+ }
+ pr_probe(p, "writeIntrThreshold is %u\n", priv->writeIntrThreshold);
+
+ /* FIFO must be empty now */
+ if (!(readb(priv->regs.ecr) & ECR_F_EMPTY)) {
+ pr_probe(p, "Can't empty FIFO\n");
+ goto fail;
+ }
+
+ /* Reset FIFO */
+ parport_ip32_set_mode(p, ECR_MODE_PS2);
+ /* Set reverse direction (must be in PS2 mode) */
+ parport_ip32_data_reverse(p);
+ /* Test FIFO, no interrupt, no DMA */
+ parport_ip32_set_mode(p, ECR_MODE_TST);
+ /* Enable interrupts */
+ parport_ip32_frob_econtrol(p, ECR_SERVINTR, 0);
+
+ /* Find out readIntrThreshold: number of PWords we can read if we get
+ * an interrupt. */
+ priv->readIntrThreshold = 0;
+ for (i = 0; i < priv->fifo_depth; i++) {
+ writeb(0xaa, priv->regs.fifo);
+ if (readb(priv->regs.ecr) & ECR_SERVINTR) {
+ /* readIntrThreshold reached */
+ priv->readIntrThreshold = i + 1;
+ break;
+ }
+ }
+ if (!priv->readIntrThreshold) {
+ pr_probe(p, "Can't get readIntrThreshold\n");
+ goto fail;
+ }
+ pr_probe(p, "readIntrThreshold is %u\n", priv->readIntrThreshold);
+
+ /* Reset ECR */
+ parport_ip32_set_mode(p, ECR_MODE_PS2);
+ parport_ip32_data_forward(p);
+ parport_ip32_set_mode(p, ECR_MODE_SPP);
+ return 1;
+
+fail:
+ priv->fifo_depth = 0;
+ parport_ip32_set_mode(p, ECR_MODE_SPP);
+ return 0;
+}
+
+/*--- Initialization code ----------------------------------------------*/
+
+/**
+ * parport_ip32_make_isa_registers - compute (ISA) register addresses
+ * @regs: pointer to &struct parport_ip32_regs to fill
+ * @base: base address of standard and EPP registers
+ * @base_hi: base address of ECP registers
+ * @regshift: how much to shift register offset by
+ *
+ * Compute register addresses, according to the ISA standard. The addresses
+ * of the standard and EPP registers are computed from address @base. The
+ * addresses of the ECP registers are computed from address @base_hi.
+ */
+static void __init
+parport_ip32_make_isa_registers(struct parport_ip32_regs *regs,
+ void __iomem *base, void __iomem *base_hi,
+ unsigned int regshift)
+{
+#define r_base(offset) ((u8 __iomem *)base + ((offset) << regshift))
+#define r_base_hi(offset) ((u8 __iomem *)base_hi + ((offset) << regshift))
+ *regs = (struct parport_ip32_regs){
+ .data = r_base(0),
+ .dsr = r_base(1),
+ .dcr = r_base(2),
+ .eppAddr = r_base(3),
+ .eppData0 = r_base(4),
+ .eppData1 = r_base(5),
+ .eppData2 = r_base(6),
+ .eppData3 = r_base(7),
+ .ecpAFifo = r_base(0),
+ .fifo = r_base_hi(0),
+ .cnfgA = r_base_hi(0),
+ .cnfgB = r_base_hi(1),
+ .ecr = r_base_hi(2)
+ };
+#undef r_base_hi
+#undef r_base
+}
+
+/**
+ * parport_ip32_probe_port - probe and register IP32 built-in parallel port
+ *
+ * Returns the new allocated &parport structure. On error, an error code is
+ * encoded in return value with the ERR_PTR function.
+ */
+static __init struct parport *parport_ip32_probe_port(void)
+{
+ struct parport_ip32_regs regs;
+ struct parport_ip32_private *priv = NULL;
+ struct parport_operations *ops = NULL;
+ struct parport *p = NULL;
+ int err;
+
+ parport_ip32_make_isa_registers(&regs, &mace->isa.parallel,
+ &mace->isa.ecp1284, 8 /* regshift */);
+
+ ops = kmalloc(sizeof(struct parport_operations), GFP_KERNEL);
+ priv = kmalloc(sizeof(struct parport_ip32_private), GFP_KERNEL);
+ p = parport_register_port(0, PARPORT_IRQ_NONE, PARPORT_DMA_NONE, ops);
+ if (ops == NULL || priv == NULL || p == NULL) {
+ err = -ENOMEM;
+ goto fail;
+ }
+ p->base = MACE_BASE + offsetof(struct sgi_mace, isa.parallel);
+ p->base_hi = MACE_BASE + offsetof(struct sgi_mace, isa.ecp1284);
+ p->private_data = priv;
+
+ *ops = parport_ip32_ops;
+ *priv = (struct parport_ip32_private){
+ .regs = regs,
+ .dcr_writable = DCR_DIR | DCR_SELECT | DCR_nINIT |
+ DCR_AUTOFD | DCR_STROBE,
+ .irq_mode = PARPORT_IP32_IRQ_FWD,
+ };
+ init_completion(&priv->irq_complete);
+
+ /* Probe port. */
+ if (!parport_ip32_ecp_supported(p)) {
+ err = -ENODEV;
+ goto fail;
+ }
+ parport_ip32_dump_state(p, "begin init", 0);
+
+ /* We found what looks like a working ECR register. Simply assume
+ * that all modes are correctly supported. Enable basic modes. */
+ p->modes = PARPORT_MODE_PCSPP | PARPORT_MODE_SAFEININT;
+ p->modes |= PARPORT_MODE_TRISTATE;
+
+ if (!parport_ip32_fifo_supported(p)) {
+ printk(KERN_WARNING PPIP32
+ "%s: error: FIFO disabled\n", p->name);
+ /* Disable hardware modes depending on a working FIFO. */
+ features &= ~PARPORT_IP32_ENABLE_SPP;
+ features &= ~PARPORT_IP32_ENABLE_ECP;
+ /* DMA is not needed if FIFO is not supported. */
+ features &= ~PARPORT_IP32_ENABLE_DMA;
+ }
+
+ /* Request IRQ */
+ if (features & PARPORT_IP32_ENABLE_IRQ) {
+ int irq = MACEISA_PARALLEL_IRQ;
+ if (request_irq(irq, parport_ip32_interrupt, 0, p->name, p)) {
+ printk(KERN_WARNING PPIP32
+ "%s: error: IRQ disabled\n", p->name);
+ /* DMA cannot work without interrupts. */
+ features &= ~PARPORT_IP32_ENABLE_DMA;
+ } else {
+ pr_probe(p, "Interrupt support enabled\n");
+ p->irq = irq;
+ priv->dcr_writable |= DCR_IRQ;
+ }
+ }
+
+ /* Allocate DMA resources */
+ if (features & PARPORT_IP32_ENABLE_DMA) {
+ if (parport_ip32_dma_register())
+ printk(KERN_WARNING PPIP32
+ "%s: error: DMA disabled\n", p->name);
+ else {
+ pr_probe(p, "DMA support enabled\n");
+ p->dma = 0; /* arbitrary value != PARPORT_DMA_NONE */
+ p->modes |= PARPORT_MODE_DMA;
+ }
+ }
+
+ if (features & PARPORT_IP32_ENABLE_SPP) {
+ /* Enable compatibility FIFO mode */
+ p->ops->compat_write_data = parport_ip32_compat_write_data;
+ p->modes |= PARPORT_MODE_COMPAT;
+ pr_probe(p, "Hardware support for SPP mode enabled\n");
+ }
+ if (features & PARPORT_IP32_ENABLE_EPP) {
+ /* Set up access functions to use EPP hardware. */
+ p->ops->epp_read_data = parport_ip32_epp_read_data;
+ p->ops->epp_write_data = parport_ip32_epp_write_data;
+ p->ops->epp_read_addr = parport_ip32_epp_read_addr;
+ p->ops->epp_write_addr = parport_ip32_epp_write_addr;
+ p->modes |= PARPORT_MODE_EPP;
+ pr_probe(p, "Hardware support for EPP mode enabled\n");
+ }
+ if (features & PARPORT_IP32_ENABLE_ECP) {
+ /* Enable ECP FIFO mode */
+ p->ops->ecp_write_data = parport_ip32_ecp_write_data;
+ /* FIXME - not implemented */
+/* p->ops->ecp_read_data = parport_ip32_ecp_read_data; */
+/* p->ops->ecp_write_addr = parport_ip32_ecp_write_addr; */
+ p->modes |= PARPORT_MODE_ECP;
+ pr_probe(p, "Hardware support for ECP mode enabled\n");
+ }
+
+ /* Initialize the port with sensible values */
+ parport_ip32_set_mode(p, ECR_MODE_PS2);
+ parport_ip32_write_control(p, DCR_SELECT | DCR_nINIT);
+ parport_ip32_data_forward(p);
+ parport_ip32_disable_irq(p);
+ parport_ip32_write_data(p, 0x00);
+ parport_ip32_dump_state(p, "end init", 0);
+
+ /* Print out what we found */
+ printk(KERN_INFO "%s: SGI IP32 at 0x%lx (0x%lx)",
+ p->name, p->base, p->base_hi);
+ if (p->irq != PARPORT_IRQ_NONE)
+ printk(", irq %d", p->irq);
+ printk(" [");
+#define printmode(x) if (p->modes & PARPORT_MODE_##x) \
+ printk("%s%s", f++ ? "," : "", #x)
+ {
+ unsigned int f = 0;
+ printmode(PCSPP);
+ printmode(TRISTATE);
+ printmode(COMPAT);
+ printmode(EPP);
+ printmode(ECP);
+ printmode(DMA);
+ }
+#undef printmode
+ printk("]\n");
+
+ parport_announce_port(p);
+ return p;
+
+fail:
+ if (p)
+ parport_put_port(p);
+ kfree(priv);
+ kfree(ops);
+ return ERR_PTR(err);
+}
+
+/**
+ * parport_ip32_unregister_port - unregister a parallel port
+ * @p: pointer to the &struct parport
+ *
+ * Unregisters a parallel port and free previously allocated resources
+ * (memory, IRQ, ...).
+ */
+static __exit void parport_ip32_unregister_port(struct parport *p)
+{
+ struct parport_ip32_private * const priv = p->physport->private_data;
+ struct parport_operations *ops = p->ops;
+
+ parport_remove_port(p);
+ if (p->modes & PARPORT_MODE_DMA)
+ parport_ip32_dma_unregister();
+ if (p->irq != PARPORT_IRQ_NONE)
+ free_irq(p->irq, p);
+ parport_put_port(p);
+ kfree(priv);
+ kfree(ops);
+}
+
+/**
+ * parport_ip32_init - module initialization function
+ */
+static int __init parport_ip32_init(void)
+{
+ pr_info(PPIP32 "SGI IP32 built-in parallel port driver v0.6\n");
+ pr_debug1(PPIP32 "Compiled on %s, %s\n", __DATE__, __TIME__);
+ this_port = parport_ip32_probe_port();
+ return IS_ERR(this_port) ? PTR_ERR(this_port) : 0;
+}
+
+/**
+ * parport_ip32_exit - module termination function
+ */
+static void __exit parport_ip32_exit(void)
+{
+ parport_ip32_unregister_port(this_port);
+}
+
+/*--- Module stuff -----------------------------------------------------*/
+
+MODULE_AUTHOR("Arnaud Giersch <arnaud.giersch@free.fr>");
+MODULE_DESCRIPTION("SGI IP32 built-in parallel port driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.6"); /* update in parport_ip32_init() too */
+
+module_init(parport_ip32_init);
+module_exit(parport_ip32_exit);
+
+module_param(verbose_probing, bool, S_IRUGO);
+MODULE_PARM_DESC(verbose_probing, "Log chit-chat during initialization");
+
+module_param(features, uint, S_IRUGO);
+MODULE_PARM_DESC(features,
+ "Bit mask of features to enable"
+ ", bit 0: IRQ support"
+ ", bit 1: DMA support"
+ ", bit 2: hardware SPP mode"
+ ", bit 3: hardware EPP mode"
+ ", bit 4: hardware ECP mode");
+
+/*--- Inform (X)Emacs about preferred coding style ---------------------*/
+/*
+ * Local Variables:
+ * mode: c
+ * c-file-style: "linux"
+ * indent-tabs-mode: t
+ * tab-width: 8
+ * fill-column: 78
+ * ispell-local-dictionary: "american"
+ * End:
+ */
diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c
index 76dd077e318..166de350778 100644
--- a/drivers/parport/parport_serial.c
+++ b/drivers/parport/parport_serial.c
@@ -329,9 +329,9 @@ static int __devinit parport_register (struct pci_dev *dev,
if (priv->num_par == ARRAY_SIZE (priv->port)) {
printk (KERN_WARNING
- "parport_serial: %s: only %u parallel ports "
+ "parport_serial: %s: only %zu parallel ports "
"supported (%d reported)\n", pci_name (dev),
- ARRAY_SIZE (priv->port), card->numports);
+ ARRAY_SIZE(priv->port), card->numports);
break;
}
diff --git a/drivers/parport/probe.c b/drivers/parport/probe.c
index b62aee8de3c..ea83b70e0de 100644
--- a/drivers/parport/probe.c
+++ b/drivers/parport/probe.c
@@ -199,7 +199,7 @@ static ssize_t parport_read_device_id (struct parport *port, char *buffer,
if (port->physport->ieee1284.phase != IEEE1284_PH_HBUSY_DAVAIL) {
if (belen != len) {
- printk (KERN_DEBUG "%s: Device ID was %d bytes"
+ printk (KERN_DEBUG "%s: Device ID was %zd bytes"
" while device told it would be %d"
" bytes\n",
port->name, len, belen);
@@ -214,7 +214,7 @@ static ssize_t parport_read_device_id (struct parport *port, char *buffer,
if (buffer[len-1] == ';') {
printk (KERN_DEBUG "%s: Device ID reading stopped"
" before device told data not available. "
- "Current idlen %d of %d, len bytes %02X %02X\n",
+ "Current idlen %u of %u, len bytes %02X %02X\n",
port->name, current_idlen, numidlens,
length[0], length[1]);
goto done;
diff --git a/drivers/s390/block/Kconfig b/drivers/s390/block/Kconfig
index 6f50cc9323d..6912399d093 100644
--- a/drivers/s390/block/Kconfig
+++ b/drivers/s390/block/Kconfig
@@ -55,13 +55,21 @@ config DASD_DIAG
Disks under VM. If you are not running under VM or unsure what it is,
say "N".
+config DASD_EER
+ tristate "Extended error reporting (EER)"
+ depends on DASD
+ help
+ This driver provides a character device interface to the
+ DASD extended error reporting. This is only needed if you want to
+ use applications written for the EER facility.
+
config DASD_CMB
tristate "Compatibility interface for DASD channel measurement blocks"
depends on DASD
help
- This driver provides an additional interface to the channel measurement
- facility, which is normally accessed though sysfs, with a set of
- ioctl functions specific to the dasd driver.
+ This driver provides an additional interface to the channel
+ measurement facility, which is normally accessed though sysfs, with
+ a set of ioctl functions specific to the dasd driver.
This is only needed if you want to use applications written for
linux-2.4 dasd channel measurement facility interface.
diff --git a/drivers/s390/block/Makefile b/drivers/s390/block/Makefile
index 58c6780134f..0c0d871e8f5 100644
--- a/drivers/s390/block/Makefile
+++ b/drivers/s390/block/Makefile
@@ -5,6 +5,7 @@
dasd_eckd_mod-objs := dasd_eckd.o dasd_3990_erp.o dasd_9343_erp.o
dasd_fba_mod-objs := dasd_fba.o dasd_3370_erp.o dasd_9336_erp.o
dasd_diag_mod-objs := dasd_diag.o
+dasd_eer_mod-objs := dasd_eer.o
dasd_mod-objs := dasd.o dasd_ioctl.o dasd_proc.o dasd_devmap.o \
dasd_genhd.o dasd_erp.o
@@ -13,5 +14,6 @@ obj-$(CONFIG_DASD_DIAG) += dasd_diag_mod.o
obj-$(CONFIG_DASD_ECKD) += dasd_eckd_mod.o
obj-$(CONFIG_DASD_FBA) += dasd_fba_mod.o
obj-$(CONFIG_DASD_CMB) += dasd_cmb.o
+obj-$(CONFIG_DASD_EER) += dasd_eer.o
obj-$(CONFIG_BLK_DEV_XPRAM) += xpram.o
obj-$(CONFIG_DCSSBLK) += dcssblk.o
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index abdf1ee633e..08c88fcd896 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/buffer_head.h>
#include <linux/hdreg.h>
+#include <linux/notifier.h>
#include <asm/ccwdev.h>
#include <asm/ebcdic.h>
@@ -57,6 +58,7 @@ static void dasd_int_handler(struct ccw_device *, unsigned long, struct irb *);
static void dasd_flush_ccw_queue(struct dasd_device *, int);
static void dasd_tasklet(struct dasd_device *);
static void do_kick_device(void *data);
+static void dasd_disable_eer(struct dasd_device *device);
/*
* SECTION: Operations on the device structure.
@@ -151,6 +153,8 @@ dasd_state_new_to_known(struct dasd_device *device)
static inline void
dasd_state_known_to_new(struct dasd_device * device)
{
+ /* disable extended error reporting for this device */
+ dasd_disable_eer(device);
/* Forget the discipline information. */
device->discipline = NULL;
device->state = DASD_STATE_NEW;
@@ -867,6 +871,9 @@ dasd_handle_state_change_pending(struct dasd_device *device)
struct dasd_ccw_req *cqr;
struct list_head *l, *n;
+ /* first of all call extended error reporting */
+ dasd_write_eer_trigger(DASD_EER_STATECHANGE, device, NULL);
+
device->stopped &= ~DASD_STOPPED_PENDING;
/* restart all 'running' IO on queue */
@@ -1086,6 +1093,19 @@ restart:
}
goto restart;
}
+
+ /* first of all call extended error reporting */
+ if (device->eer && cqr->status == DASD_CQR_FAILED) {
+ dasd_write_eer_trigger(DASD_EER_FATALERROR,
+ device, cqr);
+
+ /* restart request */
+ cqr->status = DASD_CQR_QUEUED;
+ cqr->retries = 255;
+ device->stopped |= DASD_STOPPED_QUIESCE;
+ goto restart;
+ }
+
/* Process finished ERP request. */
if (cqr->refers) {
__dasd_process_erp(device, cqr);
@@ -1223,7 +1243,8 @@ __dasd_start_head(struct dasd_device * device)
cqr = list_entry(device->ccw_queue.next, struct dasd_ccw_req, list);
/* check FAILFAST */
if (device->stopped & ~DASD_STOPPED_PENDING &&
- test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags)) {
+ test_bit(DASD_CQR_FLAGS_FAILFAST, &cqr->flags) &&
+ (!device->eer)) {
cqr->status = DASD_CQR_FAILED;
dasd_schedule_bh(device);
}
@@ -1965,6 +1986,9 @@ dasd_generic_notify(struct ccw_device *cdev, int event)
switch (event) {
case CIO_GONE:
case CIO_NO_PATH:
+ /* first of all call extended error reporting */
+ dasd_write_eer_trigger(DASD_EER_NOPATH, device, NULL);
+
if (device->state < DASD_STATE_BASIC)
break;
/* Device is active. We want to keep it. */
@@ -2022,6 +2046,51 @@ dasd_generic_auto_online (struct ccw_driver *dasd_discipline_driver)
put_driver(drv);
}
+/*
+ * notifications for extended error reports
+ */
+static struct notifier_block *dasd_eer_chain;
+
+int
+dasd_register_eer_notifier(struct notifier_block *nb)
+{
+ return notifier_chain_register(&dasd_eer_chain, nb);
+}
+
+int
+dasd_unregister_eer_notifier(struct notifier_block *nb)
+{
+ return notifier_chain_unregister(&dasd_eer_chain, nb);
+}
+
+/*
+ * Notify the registered error reporting module of a problem
+ */
+void
+dasd_write_eer_trigger(unsigned int id, struct dasd_device *device,
+ struct dasd_ccw_req *cqr)
+{
+ if (device->eer) {
+ struct dasd_eer_trigger temp;
+ temp.id = id;
+ temp.device = device;
+ temp.cqr = cqr;
+ notifier_call_chain(&dasd_eer_chain, DASD_EER_TRIGGER,
+ (void *)&temp);
+ }
+}
+
+/*
+ * Tell the registered error reporting module to disable error reporting for
+ * a given device and to cleanup any private data structures on that device.
+ */
+static void
+dasd_disable_eer(struct dasd_device *device)
+{
+ notifier_call_chain(&dasd_eer_chain, DASD_EER_DISABLE, (void *)device);
+}
+
+
static int __init
dasd_init(void)
{
@@ -2103,6 +2172,11 @@ EXPORT_SYMBOL_GPL(dasd_generic_set_online);
EXPORT_SYMBOL_GPL(dasd_generic_set_offline);
EXPORT_SYMBOL_GPL(dasd_generic_auto_online);
+EXPORT_SYMBOL(dasd_register_eer_notifier);
+EXPORT_SYMBOL(dasd_unregister_eer_notifier);
+EXPORT_SYMBOL(dasd_write_eer_trigger);
+
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
diff --git a/drivers/s390/block/dasd_3990_erp.c b/drivers/s390/block/dasd_3990_erp.c
index 4ee0f934e32..c811380b907 100644
--- a/drivers/s390/block/dasd_3990_erp.c
+++ b/drivers/s390/block/dasd_3990_erp.c
@@ -1108,6 +1108,9 @@ dasd_3990_handle_env_data(struct dasd_ccw_req * erp, char *sense)
case 0x0B:
DEV_MESSAGE(KERN_WARNING, device, "%s",
"FORMAT F - Volume is suspended duplex");
+ /* call extended error reporting (EER) */
+ dasd_write_eer_trigger(DASD_EER_PPRCSUSPEND, device,
+ erp->refers);
break;
case 0x0C:
DEV_MESSAGE(KERN_WARNING, device, "%s",
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
index bc3823d3522..e15dd797805 100644
--- a/drivers/s390/block/dasd_eckd.h
+++ b/drivers/s390/block/dasd_eckd.h
@@ -29,6 +29,7 @@
#define DASD_ECKD_CCW_PSF 0x27
#define DASD_ECKD_CCW_RSSD 0x3e
#define DASD_ECKD_CCW_LOCATE_RECORD 0x47
+#define DASD_ECKD_CCW_SNSS 0x54
#define DASD_ECKD_CCW_DEFINE_EXTENT 0x63
#define DASD_ECKD_CCW_WRITE_MT 0x85
#define DASD_ECKD_CCW_READ_MT 0x86
diff --git a/drivers/s390/block/dasd_eer.c b/drivers/s390/block/dasd_eer.c
new file mode 100644
index 00000000000..f70cd7716b2
--- /dev/null
+++ b/drivers/s390/block/dasd_eer.c
@@ -0,0 +1,1090 @@
+/*
+ * character device driver for extended error reporting
+ *
+ *
+ * Copyright (C) 2005 IBM Corporation
+ * extended error reporting for DASD ECKD devices
+ * Author(s): Stefan Weinhuber <wein@de.ibm.com>
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/workqueue.h>
+#include <linux/poll.h>
+#include <linux/notifier.h>
+
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+#include <asm/atomic.h>
+#include <asm/ebcdic.h>
+
+#include "dasd_int.h"
+#include "dasd_eckd.h"
+
+
+MODULE_LICENSE("GPL");
+
+MODULE_AUTHOR("Stefan Weinhuber <wein@de.ibm.com>");
+MODULE_DESCRIPTION("DASD extended error reporting module");
+
+
+#ifdef PRINTK_HEADER
+#undef PRINTK_HEADER
+#endif /* PRINTK_HEADER */
+#define PRINTK_HEADER "dasd(eer):"
+
+
+
+
+
+/*****************************************************************************/
+/* the internal buffer */
+/*****************************************************************************/
+
+/*
+ * The internal buffer is meant to store obaque blobs of data, so it doesn't
+ * know of higher level concepts like triggers.
+ * It consists of a number of pages that are used as a ringbuffer. Each data
+ * blob is stored in a simple record that consists of an integer, which
+ * contains the size of the following data, and the data bytes themselfes.
+ *
+ * To allow for multiple independent readers we create one internal buffer
+ * each time the device is opened and destroy the buffer when the file is
+ * closed again.
+ *
+ * One record can be written to a buffer by using the functions
+ * - dasd_eer_start_record (one time per record to write the size to the buffer
+ * and reserve the space for the data)
+ * - dasd_eer_write_buffer (one or more times per record to write the data)
+ * The data can be written in several steps but you will have to compute
+ * the total size up front for the invocation of dasd_eer_start_record.
+ * If the ringbuffer is full, dasd_eer_start_record will remove the required
+ * number of old records.
+ *
+ * A record is typically read in two steps, first read the integer that
+ * specifies the size of the following data, then read the data.
+ * Both can be done by
+ * - dasd_eer_read_buffer
+ *
+ * For all mentioned functions you need to get the bufferlock first and keep it
+ * until a complete record is written or read.
+ */
+
+
+/*
+ * Alle information necessary to keep track of an internal buffer is kept in
+ * a struct eerbuffer. The buffer specific to a file pointer is strored in
+ * the private_data field of that file. To be able to write data to all
+ * existing buffers, each buffer is also added to the bufferlist.
+ * If the user doesn't want to read a complete record in one go, we have to
+ * keep track of the rest of the record. residual stores the number of bytes
+ * that are still to deliver. If the rest of the record is invalidated between
+ * two reads then residual will be set to -1 so that the next read will fail.
+ * All entries in the eerbuffer structure are protected with the bufferlock.
+ * To avoid races between writing to a buffer on the one side and creating
+ * and destroying buffers on the other side, the bufferlock must also be used
+ * to protect the bufferlist.
+ */
+
+struct eerbuffer {
+ struct list_head list;
+ char **buffer;
+ int buffersize;
+ int buffer_page_count;
+ int head;
+ int tail;
+ int residual;
+};
+
+LIST_HEAD(bufferlist);
+
+static spinlock_t bufferlock = SPIN_LOCK_UNLOCKED;
+
+DECLARE_WAIT_QUEUE_HEAD(dasd_eer_read_wait_queue);
+
+/*
+ * How many free bytes are available on the buffer.
+ * needs to be called with bufferlock held
+ */
+static int
+dasd_eer_get_free_bytes(struct eerbuffer *eerb)
+{
+ if (eerb->head < eerb->tail) {
+ return eerb->tail - eerb->head - 1;
+ } else
+ return eerb->buffersize - eerb->head + eerb->tail -1;
+}
+
+/*
+ * How many bytes of buffer space are used.
+ * needs to be called with bufferlock held
+ */
+static int
+dasd_eer_get_filled_bytes(struct eerbuffer *eerb)
+{
+
+ if (eerb->head >= eerb->tail) {
+ return eerb->head - eerb->tail;
+ } else
+ return eerb->buffersize - eerb->tail + eerb->head;
+}
+
+/*
+ * The dasd_eer_write_buffer function just copies count bytes of data
+ * to the buffer. Make sure to call dasd_eer_start_record first, to
+ * make sure that enough free space is available.
+ * needs to be called with bufferlock held
+ */
+static void
+dasd_eer_write_buffer(struct eerbuffer *eerb, int count, char *data)
+{
+
+ unsigned long headindex,localhead;
+ unsigned long rest, len;
+ char *nextdata;
+
+ nextdata = data;
+ rest = count;
+ while (rest > 0) {
+ headindex = eerb->head / PAGE_SIZE;
+ localhead = eerb->head % PAGE_SIZE;
+ len = min(rest, (PAGE_SIZE - localhead));
+ memcpy(eerb->buffer[headindex]+localhead, nextdata, len);
+ nextdata += len;
+ rest -= len;
+ eerb->head += len;
+ if ( eerb->head == eerb->buffersize )
+ eerb->head = 0; /* wrap around */
+ if (eerb->head > eerb->buffersize) {
+ MESSAGE(KERN_ERR, "%s", "runaway buffer head.");
+ BUG();
+ }
+ }
+}
+
+/*
+ * needs to be called with bufferlock held
+ */
+static int
+dasd_eer_read_buffer(struct eerbuffer *eerb, int count, char *data)
+{
+
+ unsigned long tailindex,localtail;
+ unsigned long rest, len, finalcount;
+ char *nextdata;
+
+ finalcount = min(count, dasd_eer_get_filled_bytes(eerb));
+ nextdata = data;
+ rest = finalcount;
+ while (rest > 0) {
+ tailindex = eerb->tail / PAGE_SIZE;
+ localtail = eerb->tail % PAGE_SIZE;
+ len = min(rest, (PAGE_SIZE - localtail));
+ memcpy(nextdata, eerb->buffer[tailindex]+localtail, len);
+ nextdata += len;
+ rest -= len;
+ eerb->tail += len;
+ if ( eerb->tail == eerb->buffersize )
+ eerb->tail = 0; /* wrap around */
+ if (eerb->tail > eerb->buffersize) {
+ MESSAGE(KERN_ERR, "%s", "runaway buffer tail.");
+ BUG();
+ }
+ }
+ return finalcount;
+}
+
+/*
+ * Whenever you want to write a blob of data to the internal buffer you
+ * have to start by using this function first. It will write the number
+ * of bytes that will be written to the buffer. If necessary it will remove
+ * old records to make room for the new one.
+ * needs to be called with bufferlock held
+ */
+static int
+dasd_eer_start_record(struct eerbuffer *eerb, int count)
+{
+ int tailcount;
+ if (count + sizeof(count) > eerb->buffersize)
+ return -ENOMEM;
+ while (dasd_eer_get_free_bytes(eerb) < count + sizeof(count)) {
+ if (eerb->residual > 0) {
+ eerb->tail += eerb->residual;
+ if (eerb->tail >= eerb->buffersize)
+ eerb->tail -= eerb->buffersize;
+ eerb->residual = -1;
+ }
+ dasd_eer_read_buffer(eerb, sizeof(tailcount),
+ (char*)(&tailcount));
+ eerb->tail += tailcount;
+ if (eerb->tail >= eerb->buffersize)
+ eerb->tail -= eerb->buffersize;
+ }
+ dasd_eer_write_buffer(eerb, sizeof(count), (char*)(&count));
+
+ return 0;
+};
+
+/*
+ * release pages that are not used anymore
+ */
+static void
+dasd_eer_free_buffer_pages(char **buf, int no_pages)
+{
+ int i;
+
+ for (i = 0; i < no_pages; ++i) {
+ free_page((unsigned long)buf[i]);
+ }
+}
+
+/*
+ * allocate a new set of memory pages
+ */
+static int
+dasd_eer_allocate_buffer_pages(char **buf, int no_pages)
+{
+ int i;
+
+ for (i = 0; i < no_pages; ++i) {
+ buf[i] = (char *) get_zeroed_page(GFP_KERNEL);
+ if (!buf[i]) {
+ dasd_eer_free_buffer_pages(buf, i);
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
+/*
+ * empty the buffer by resetting head and tail
+ * In case there is a half read data blob in the buffer, we set residual
+ * to -1 to indicate that the remainder of the blob is lost.
+ */
+static void
+dasd_eer_purge_buffer(struct eerbuffer *eerb)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&bufferlock, flags);
+ if (eerb->residual > 0)
+ eerb->residual = -1;
+ eerb->tail=0;
+ eerb->head=0;
+ spin_unlock_irqrestore(&bufferlock, flags);
+}
+
+/*
+ * set the size of the buffer, newsize is the new number of pages to be used
+ * we don't try to copy any data back an forth, so any resize will also purge
+ * the buffer
+ */
+static int
+dasd_eer_resize_buffer(struct eerbuffer *eerb, int newsize)
+{
+ int i, oldcount, reuse;
+ char **new;
+ char **old;
+ unsigned long flags;
+
+ if (newsize < 1)
+ return -EINVAL;
+ if (eerb->buffer_page_count == newsize) {
+ /* documented behaviour is that any successfull invocation
+ * will purge all records */
+ dasd_eer_purge_buffer(eerb);
+ return 0;
+ }
+ new = kmalloc(newsize*sizeof(char*), GFP_KERNEL);
+ if (!new)
+ return -ENOMEM;
+
+ reuse=min(eerb->buffer_page_count, newsize);
+ for (i = 0; i < reuse; ++i) {
+ new[i] = eerb->buffer[i];
+ }
+ if (eerb->buffer_page_count < newsize) {
+ if (dasd_eer_allocate_buffer_pages(
+ &new[eerb->buffer_page_count],
+ newsize - eerb->buffer_page_count)) {
+ kfree(new);
+ return -ENOMEM;
+ }
+ }
+
+ spin_lock_irqsave(&bufferlock, flags);
+ old = eerb->buffer;
+ eerb->buffer = new;
+ if (eerb->residual > 0)
+ eerb->residual = -1;
+ eerb->tail = 0;
+ eerb->head = 0;
+ oldcount = eerb->buffer_page_count;
+ eerb->buffer_page_count = newsize;
+ spin_unlock_irqrestore(&bufferlock, flags);
+
+ if (oldcount > newsize) {
+ for (i = newsize; i < oldcount; ++i) {
+ free_page((unsigned long)old[i]);
+ }
+ }
+ kfree(old);
+
+ return 0;
+}
+
+
+/*****************************************************************************/
+/* The extended error reporting functionality */
+/*****************************************************************************/
+
+/*
+ * When a DASD device driver wants to report an error, it calls the
+ * function dasd_eer_write_trigger (via a notifier mechanism) and gives the
+ * respective trigger ID as parameter.
+ * Currently there are four kinds of triggers:
+ *
+ * DASD_EER_FATALERROR: all kinds of unrecoverable I/O problems
+ * DASD_EER_PPRCSUSPEND: PPRC was suspended
+ * DASD_EER_NOPATH: There is no path to the device left.
+ * DASD_EER_STATECHANGE: The state of the device has changed.
+ *
+ * For the first three triggers all required information can be supplied by
+ * the caller. For these triggers a record is written by the function
+ * dasd_eer_write_standard_trigger.
+ *
+ * When dasd_eer_write_trigger is called to write a DASD_EER_STATECHANGE
+ * trigger, we have to gather the necessary sense data first. We cannot queue
+ * the necessary SNSS (sense subsystem status) request immediatly, since we
+ * are likely to run in a deadlock situation. Instead, we schedule a
+ * work_struct that calls the function dasd_eer_sense_subsystem_status to
+ * create and start an SNSS request asynchronously.
+ *
+ * To avoid memory allocations at runtime, the necessary memory is allocated
+ * when the extended error reporting is enabled for a device (by
+ * dasd_eer_probe). There is one private eer data structure for each eer
+ * enabled DASD device. It contains memory for the work_struct, one SNSS cqr
+ * and a flags field that is used to coordinate the use of the cqr. The call
+ * to write a state change trigger can come in at any time, so we have one flag
+ * CQR_IN_USE that protects the cqr itself. When this flag indicates that the
+ * cqr is currently in use, dasd_eer_sense_subsystem_status cannot start a
+ * second request but sets the SNSS_REQUESTED flag instead.
+ *
+ * When the request is finished, the callback function dasd_eer_SNSS_cb
+ * is called. This function will invoke the function
+ * dasd_eer_write_SNSS_trigger to finally write the trigger. It will also
+ * check the SNSS_REQUESTED flag and if it is set it will call
+ * dasd_eer_sense_subsystem_status again.
+ *
+ * To avoid race conditions during the handling of the lock, the flags must
+ * be protected by the snsslock.
+ */
+
+struct dasd_eer_private {
+ struct dasd_ccw_req *cqr;
+ unsigned long flags;
+ struct work_struct worker;
+};
+
+static void dasd_eer_destroy(struct dasd_device *device,
+ struct dasd_eer_private *eer);
+static int
+dasd_eer_write_trigger(struct dasd_eer_trigger *trigger);
+static void dasd_eer_sense_subsystem_status(void *data);
+static int dasd_eer_notify(struct notifier_block *self,
+ unsigned long action, void *data);
+
+struct workqueue_struct *dasd_eer_workqueue;
+
+#define SNSS_DATA_SIZE 44
+static spinlock_t snsslock = SPIN_LOCK_UNLOCKED;
+
+#define DASD_EER_BUSID_SIZE 10
+struct dasd_eer_header {
+ __u32 total_size;
+ __u32 trigger;
+ __u64 tv_sec;
+ __u64 tv_usec;
+ char busid[DASD_EER_BUSID_SIZE];
+} __attribute__ ((packed));
+
+static struct notifier_block dasd_eer_nb = {
+ .notifier_call = dasd_eer_notify,
+};
+
+/*
+ * flags for use with dasd_eer_private
+ */
+#define CQR_IN_USE 0
+#define SNSS_REQUESTED 1
+
+/*
+ * This function checks if extended error reporting is available for a given
+ * dasd_device. If yes, then it creates and returns a struct dasd_eer,
+ * otherwise it returns an -EPERM error pointer.
+ */
+struct dasd_eer_private *
+dasd_eer_probe(struct dasd_device *device)
+{
+ struct dasd_eer_private *private;
+
+ if (!(device && device->discipline
+ && !strcmp(device->discipline->name, "ECKD"))) {
+ return ERR_PTR(-EPERM);
+ }
+ /* allocate the private data structure */
+ private = (struct dasd_eer_private *)kmalloc(
+ sizeof(struct dasd_eer_private), GFP_KERNEL);
+ if (!private) {
+ return ERR_PTR(-ENOMEM);
+ }
+ INIT_WORK(&private->worker, dasd_eer_sense_subsystem_status,
+ (void *)device);
+ private->cqr = dasd_kmalloc_request("ECKD",
+ 1 /* SNSS */ ,
+ SNSS_DATA_SIZE ,
+ device);
+ if (!private->cqr) {
+ kfree(private);
+ return ERR_PTR(-ENOMEM);
+ }
+ private->flags = 0;
+ return private;
+};
+
+/*
+ * If our private SNSS request is queued, remove it from the
+ * dasd ccw queue so we can free the requests memory.
+ */
+static void
+dasd_eer_dequeue_SNSS_request(struct dasd_device *device,
+ struct dasd_eer_private *eer)
+{
+ struct list_head *lst, *nxt;
+ struct dasd_ccw_req *cqr, *erpcqr;
+ dasd_erp_fn_t erp_fn;
+
+ spin_lock_irq(get_ccwdev_lock(device->cdev));
+ list_for_each_safe(lst, nxt, &device->ccw_queue) {
+ cqr = list_entry(lst, struct dasd_ccw_req, list);
+ /* we are looking for two kinds or requests */
+ /* first kind: our SNSS request: */
+ if (cqr == eer->cqr) {
+ if (cqr->status == DASD_CQR_IN_IO)
+ device->discipline->term_IO(cqr);
+ list_del(&cqr->list);
+ break;
+ }
+ /* second kind: ERP requests for our SNSS request */
+ if (cqr->refers) {
+ /* If this erp request chain ends in our cqr, then */
+ /* cal the erp_postaction to clean it up */
+ erpcqr = cqr;
+ while (erpcqr->refers) {
+ erpcqr = erpcqr->refers;
+ }
+ if (erpcqr == eer->cqr) {
+ erp_fn = device->discipline->erp_postaction(
+ cqr);
+ erp_fn(cqr);
+ }
+ continue;
+ }
+ }
+ spin_unlock_irq(get_ccwdev_lock(device->cdev));
+}
+
+/*
+ * This function dismantles a struct dasd_eer that was created by
+ * dasd_eer_probe. Since we want to free our private data structure,
+ * we must make sure that the memory is not in use anymore.
+ * We have to flush the work queue and remove a possible SNSS request
+ * from the dasd queue.
+ */
+static void
+dasd_eer_destroy(struct dasd_device *device, struct dasd_eer_private *eer)
+{
+ flush_workqueue(dasd_eer_workqueue);
+ dasd_eer_dequeue_SNSS_request(device, eer);
+ dasd_kfree_request(eer->cqr, device);
+ kfree(eer);
+};
+
+/*
+ * enable the extended error reporting for a particular device
+ */
+static int
+dasd_eer_enable_on_device(struct dasd_device *device)
+{
+ void *eer;
+ if (!device)
+ return -ENODEV;
+ if (device->eer)
+ return 0;
+ if (!try_module_get(THIS_MODULE)) {
+ return -EINVAL;
+ }
+ eer = (void *)dasd_eer_probe(device);
+ if (IS_ERR(eer)) {
+ module_put(THIS_MODULE);
+ return PTR_ERR(eer);
+ }
+ device->eer = eer;
+ return 0;
+}
+
+/*
+ * enable the extended error reporting for a particular device
+ */
+static int
+dasd_eer_disable_on_device(struct dasd_device *device)
+{
+ struct dasd_eer_private *eer = device->eer;
+
+ if (!device)
+ return -ENODEV;
+ if (!device->eer)
+ return 0;
+ device->eer = NULL;
+ dasd_eer_destroy(device,eer);
+ module_put(THIS_MODULE);
+
+ return 0;
+}
+
+/*
+ * Set extended error reporting (eer)
+ * Note: This will be registered as a DASD ioctl, to be called on DASD devices.
+ */
+static int
+dasd_ioctl_set_eer(struct block_device *bdev, int no, long args)
+{
+ struct dasd_device *device;
+ int intval;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (bdev != bdev->bd_contains)
+ /* Error-reporting is not allowed for partitions */
+ return -EINVAL;
+ if (get_user(intval, (int __user *) args))
+ return -EFAULT;
+ device = bdev->bd_disk->private_data;
+ if (device == NULL)
+ return -ENODEV;
+
+ intval = (intval != 0);
+ DEV_MESSAGE (KERN_DEBUG, device,
+ "set eer on device to %d", intval);
+ if (intval)
+ return dasd_eer_enable_on_device(device);
+ else
+ return dasd_eer_disable_on_device(device);
+}
+
+/*
+ * Get value of extended error reporting.
+ * Note: This will be registered as a DASD ioctl, to be called on DASD devices.
+ */
+static int
+dasd_ioctl_get_eer(struct block_device *bdev, int no, long args)
+{
+ struct dasd_device *device;
+
+ device = bdev->bd_disk->private_data;
+ if (device == NULL)
+ return -ENODEV;
+ return put_user((device->eer != NULL), (int __user *) args);
+}
+
+/*
+ * The following function can be used for those triggers that have
+ * all necessary data available when the function is called.
+ * If the parameter cqr is not NULL, the chain of requests will be searched
+ * for valid sense data, and all valid sense data sets will be added to
+ * the triggers data.
+ */
+static int
+dasd_eer_write_standard_trigger(int trigger, struct dasd_device *device,
+ struct dasd_ccw_req *cqr)
+{
+ struct dasd_ccw_req *temp_cqr;
+ int data_size;
+ struct timeval tv;
+ struct dasd_eer_header header;
+ unsigned long flags;
+ struct eerbuffer *eerb;
+
+ /* go through cqr chain and count the valid sense data sets */
+ temp_cqr = cqr;
+ data_size = 0;
+ while (temp_cqr) {
+ if (temp_cqr->irb.esw.esw0.erw.cons)
+ data_size += 32;
+ temp_cqr = temp_cqr->refers;
+ }
+
+ header.total_size = sizeof(header) + data_size + 4; /* "EOR" */
+ header.trigger = trigger;
+ do_gettimeofday(&tv);
+ header.tv_sec = tv.tv_sec;
+ header.tv_usec = tv.tv_usec;
+ strncpy(header.busid, device->cdev->dev.bus_id, DASD_EER_BUSID_SIZE);
+
+ spin_lock_irqsave(&bufferlock, flags);
+ list_for_each_entry(eerb, &bufferlist, list) {
+ dasd_eer_start_record(eerb, header.total_size);
+ dasd_eer_write_buffer(eerb, sizeof(header), (char*)(&header));
+ temp_cqr = cqr;
+ while (temp_cqr) {
+ if (temp_cqr->irb.esw.esw0.erw.cons)
+ dasd_eer_write_buffer(eerb, 32, cqr->irb.ecw);
+ temp_cqr = temp_cqr->refers;
+ }
+ dasd_eer_write_buffer(eerb, 4,"EOR");
+ }
+ spin_unlock_irqrestore(&bufferlock, flags);
+
+ wake_up_interruptible(&dasd_eer_read_wait_queue);
+
+ return 0;
+}
+
+/*
+ * This function writes a DASD_EER_STATECHANGE trigger.
+ */
+static void
+dasd_eer_write_SNSS_trigger(struct dasd_device *device,
+ struct dasd_ccw_req *cqr)
+{
+ int data_size;
+ int snss_rc;
+ struct timeval tv;
+ struct dasd_eer_header header;
+ unsigned long flags;
+ struct eerbuffer *eerb;
+
+ snss_rc = (cqr->status == DASD_CQR_FAILED) ? -EIO : 0;
+ if (snss_rc)
+ data_size = 0;
+ else
+ data_size = SNSS_DATA_SIZE;
+
+ header.total_size = sizeof(header) + data_size + 4; /* "EOR" */
+ header.trigger = DASD_EER_STATECHANGE;
+ do_gettimeofday(&tv);
+ header.tv_sec = tv.tv_sec;
+ header.tv_usec = tv.tv_usec;
+ strncpy(header.busid, device->cdev->dev.bus_id, DASD_EER_BUSID_SIZE);
+
+ spin_lock_irqsave(&bufferlock, flags);
+ list_for_each_entry(eerb, &bufferlist, list) {
+ dasd_eer_start_record(eerb, header.total_size);
+ dasd_eer_write_buffer(eerb, sizeof(header),(char*)(&header));
+ if (!snss_rc)
+ dasd_eer_write_buffer(eerb, SNSS_DATA_SIZE, cqr->data);
+ dasd_eer_write_buffer(eerb, 4,"EOR");
+ }
+ spin_unlock_irqrestore(&bufferlock, flags);
+
+ wake_up_interruptible(&dasd_eer_read_wait_queue);
+}
+
+/*
+ * callback function for use with SNSS request
+ */
+static void
+dasd_eer_SNSS_cb(struct dasd_ccw_req *cqr, void *data)
+{
+ struct dasd_device *device;
+ struct dasd_eer_private *private;
+ unsigned long irqflags;
+
+ device = (struct dasd_device *)data;
+ private = (struct dasd_eer_private *)device->eer;
+ dasd_eer_write_SNSS_trigger(device, cqr);
+ spin_lock_irqsave(&snsslock, irqflags);
+ if(!test_and_clear_bit(SNSS_REQUESTED, &private->flags)) {
+ clear_bit(CQR_IN_USE, &private->flags);
+ spin_unlock_irqrestore(&snsslock, irqflags);
+ return;
+ };
+ clear_bit(CQR_IN_USE, &private->flags);
+ spin_unlock_irqrestore(&snsslock, irqflags);
+ dasd_eer_sense_subsystem_status(device);
+ return;
+}
+
+/*
+ * clean a used cqr before using it again
+ */
+static void
+dasd_eer_clean_SNSS_request(struct dasd_ccw_req *cqr)
+{
+ struct ccw1 *cpaddr = cqr->cpaddr;
+ void *data = cqr->data;
+
+ memset(cqr, 0, sizeof(struct dasd_ccw_req));
+ memset(cpaddr, 0, sizeof(struct ccw1));
+ memset(data, 0, SNSS_DATA_SIZE);
+ cqr->cpaddr = cpaddr;
+ cqr->data = data;
+ strncpy((char *) &cqr->magic, "ECKD", 4);
+ ASCEBC((char *) &cqr->magic, 4);
+ set_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);
+}
+
+/*
+ * build and start an SNSS request
+ * This function is called from a work queue so we have to
+ * pass the dasd_device pointer as a void pointer.
+ */
+static void
+dasd_eer_sense_subsystem_status(void *data)
+{
+ struct dasd_device *device;
+ struct dasd_eer_private *private;
+ struct dasd_ccw_req *cqr;
+ struct ccw1 *ccw;
+ unsigned long irqflags;
+
+ device = (struct dasd_device *)data;
+ private = (struct dasd_eer_private *)device->eer;
+ if (!private) /* device not eer enabled any more */
+ return;
+ cqr = private->cqr;
+ spin_lock_irqsave(&snsslock, irqflags);
+ if(test_and_set_bit(CQR_IN_USE, &private->flags)) {
+ set_bit(SNSS_REQUESTED, &private->flags);
+ spin_unlock_irqrestore(&snsslock, irqflags);
+ return;
+ };
+ spin_unlock_irqrestore(&snsslock, irqflags);
+ dasd_eer_clean_SNSS_request(cqr);
+ cqr->device = device;
+ cqr->retries = 255;
+ cqr->expires = 10 * HZ;
+
+ ccw = cqr->cpaddr;
+ ccw->cmd_code = DASD_ECKD_CCW_SNSS;
+ ccw->count = SNSS_DATA_SIZE;
+ ccw->flags = 0;
+ ccw->cda = (__u32)(addr_t)cqr->data;
+
+ cqr->buildclk = get_clock();
+ cqr->status = DASD_CQR_FILLED;
+ cqr->callback = dasd_eer_SNSS_cb;
+ cqr->callback_data = (void *)device;
+ dasd_add_request_head(cqr);
+
+ return;
+}
+
+/*
+ * This function is called for all triggers. It calls the appropriate
+ * function that writes the actual trigger records.
+ */
+static int
+dasd_eer_write_trigger(struct dasd_eer_trigger *trigger)
+{
+ int rc;
+ struct dasd_eer_private *private = trigger->device->eer;
+
+ switch (trigger->id) {
+ case DASD_EER_FATALERROR:
+ case DASD_EER_PPRCSUSPEND:
+ rc = dasd_eer_write_standard_trigger(
+ trigger->id, trigger->device, trigger->cqr);
+ break;
+ case DASD_EER_NOPATH:
+ rc = dasd_eer_write_standard_trigger(
+ trigger->id, trigger->device, NULL);
+ break;
+ case DASD_EER_STATECHANGE:
+ if (queue_work(dasd_eer_workqueue, &private->worker)) {
+ rc=0;
+ } else {
+ /* If the work_struct was already queued, it can't
+ * be queued again. But this is OK since we don't
+ * need to have it queued twice.
+ */
+ rc = -EBUSY;
+ }
+ break;
+ default: /* unknown trigger, so we write it without any sense data */
+ rc = dasd_eer_write_standard_trigger(
+ trigger->id, trigger->device, NULL);
+ break;
+ }
+ return rc;
+}
+
+/*
+ * This function is registered with the dasd device driver and gets called
+ * for all dasd eer notifications.
+ */
+static int dasd_eer_notify(struct notifier_block *self,
+ unsigned long action, void *data)
+{
+ switch (action) {
+ case DASD_EER_DISABLE:
+ dasd_eer_disable_on_device((struct dasd_device *)data);
+ break;
+ case DASD_EER_TRIGGER:
+ dasd_eer_write_trigger((struct dasd_eer_trigger *)data);
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+
+/*****************************************************************************/
+/* the device operations */
+/*****************************************************************************/
+
+/*
+ * On the one side we need a lock to access our internal buffer, on the
+ * other side a copy_to_user can sleep. So we need to copy the data we have
+ * to transfer in a readbuffer, which is protected by the readbuffer_mutex.
+ */
+static char readbuffer[PAGE_SIZE];
+DECLARE_MUTEX(readbuffer_mutex);
+
+
+static int
+dasd_eer_open(struct inode *inp, struct file *filp)
+{
+ struct eerbuffer *eerb;
+ unsigned long flags;
+
+ eerb = kmalloc(sizeof(struct eerbuffer), GFP_KERNEL);
+ eerb->head = 0;
+ eerb->tail = 0;
+ eerb->residual = 0;
+ eerb->buffer_page_count = 1;
+ eerb->buffersize = eerb->buffer_page_count * PAGE_SIZE;
+ eerb->buffer = kmalloc(eerb->buffer_page_count*sizeof(char*),
+ GFP_KERNEL);
+ if (!eerb->buffer)
+ return -ENOMEM;
+ if (dasd_eer_allocate_buffer_pages(eerb->buffer,
+ eerb->buffer_page_count)) {
+ kfree(eerb->buffer);
+ return -ENOMEM;
+ }
+ filp->private_data = eerb;
+ spin_lock_irqsave(&bufferlock, flags);
+ list_add(&eerb->list, &bufferlist);
+ spin_unlock_irqrestore(&bufferlock, flags);
+
+ return nonseekable_open(inp,filp);
+}
+
+static int
+dasd_eer_close(struct inode *inp, struct file *filp)
+{
+ struct eerbuffer *eerb;
+ unsigned long flags;
+
+ eerb = (struct eerbuffer *)filp->private_data;
+ spin_lock_irqsave(&bufferlock, flags);
+ list_del(&eerb->list);
+ spin_unlock_irqrestore(&bufferlock, flags);
+ dasd_eer_free_buffer_pages(eerb->buffer, eerb->buffer_page_count);
+ kfree(eerb->buffer);
+ kfree(eerb);
+
+ return 0;
+}
+
+static long
+dasd_eer_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ int intval;
+ struct eerbuffer *eerb;
+
+ eerb = (struct eerbuffer *)filp->private_data;
+ switch (cmd) {
+ case DASD_EER_PURGE:
+ dasd_eer_purge_buffer(eerb);
+ return 0;
+ case DASD_EER_SETBUFSIZE:
+ if (get_user(intval, (int __user *)arg))
+ return -EFAULT;
+ return dasd_eer_resize_buffer(eerb, intval);
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+static ssize_t
+dasd_eer_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
+{
+ int tc,rc;
+ int tailcount,effective_count;
+ unsigned long flags;
+ struct eerbuffer *eerb;
+
+ eerb = (struct eerbuffer *)filp->private_data;
+ if(down_interruptible(&readbuffer_mutex))
+ return -ERESTARTSYS;
+
+ spin_lock_irqsave(&bufferlock, flags);
+
+ if (eerb->residual < 0) { /* the remainder of this record */
+ /* has been deleted */
+ eerb->residual = 0;
+ spin_unlock_irqrestore(&bufferlock, flags);
+ up(&readbuffer_mutex);
+ return -EIO;
+ } else if (eerb->residual > 0) {
+ /* OK we still have a second half of a record to deliver */
+ effective_count = min(eerb->residual, (int)count);
+ eerb->residual -= effective_count;
+ } else {
+ tc = 0;
+ while (!tc) {
+ tc = dasd_eer_read_buffer(eerb,
+ sizeof(tailcount), (char*)(&tailcount));
+ if (!tc) {
+ /* no data available */
+ spin_unlock_irqrestore(&bufferlock, flags);
+ up(&readbuffer_mutex);
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+ rc = wait_event_interruptible(
+ dasd_eer_read_wait_queue,
+ eerb->head != eerb->tail);
+ if (rc) {
+ return rc;
+ }
+ if(down_interruptible(&readbuffer_mutex))
+ return -ERESTARTSYS;
+ spin_lock_irqsave(&bufferlock, flags);
+ }
+ }
+ WARN_ON(tc != sizeof(tailcount));
+ effective_count = min(tailcount,(int)count);
+ eerb->residual = tailcount - effective_count;
+ }
+
+ tc = dasd_eer_read_buffer(eerb, effective_count, readbuffer);
+ WARN_ON(tc != effective_count);
+
+ spin_unlock_irqrestore(&bufferlock, flags);
+
+ if (copy_to_user(buf, readbuffer, effective_count)) {
+ up(&readbuffer_mutex);
+ return -EFAULT;
+ }
+
+ up(&readbuffer_mutex);
+ return effective_count;
+}
+
+static unsigned int
+dasd_eer_poll (struct file *filp, poll_table *ptable)
+{
+ unsigned int mask;
+ unsigned long flags;
+ struct eerbuffer *eerb;
+
+ eerb = (struct eerbuffer *)filp->private_data;
+ poll_wait(filp, &dasd_eer_read_wait_queue, ptable);
+ spin_lock_irqsave(&bufferlock, flags);
+ if (eerb->head != eerb->tail)
+ mask = POLLIN | POLLRDNORM ;
+ else
+ mask = 0;
+ spin_unlock_irqrestore(&bufferlock, flags);
+ return mask;
+}
+
+static struct file_operations dasd_eer_fops = {
+ .open = &dasd_eer_open,
+ .release = &dasd_eer_close,
+ .unlocked_ioctl = &dasd_eer_ioctl,
+ .compat_ioctl = &dasd_eer_ioctl,
+ .read = &dasd_eer_read,
+ .poll = &dasd_eer_poll,
+ .owner = THIS_MODULE,
+};
+
+static struct miscdevice dasd_eer_dev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "dasd_eer",
+ .fops = &dasd_eer_fops,
+};
+
+
+/*****************************************************************************/
+/* Init and exit */
+/*****************************************************************************/
+
+static int
+__init dasd_eer_init(void)
+{
+ int rc;
+
+ dasd_eer_workqueue = create_singlethread_workqueue("dasd_eer");
+ if (!dasd_eer_workqueue) {
+ MESSAGE(KERN_ERR , "%s", "dasd_eer_init could not "
+ "create workqueue \n");
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ rc = dasd_register_eer_notifier(&dasd_eer_nb);
+ if (rc) {
+ MESSAGE(KERN_ERR, "%s", "dasd_eer_init could not "
+ "register error reporting");
+ goto queue;
+ }
+
+ dasd_ioctl_no_register(THIS_MODULE, BIODASDEERSET, dasd_ioctl_set_eer);
+ dasd_ioctl_no_register(THIS_MODULE, BIODASDEERGET, dasd_ioctl_get_eer);
+
+ /* we don't need our own character device,
+ * so we just register as misc device */
+ rc = misc_register(&dasd_eer_dev);
+ if (rc) {
+ MESSAGE(KERN_ERR, "%s", "dasd_eer_init could not "
+ "register misc device");
+ goto unregister;
+ }
+
+ return 0;
+
+unregister:
+ dasd_unregister_eer_notifier(&dasd_eer_nb);
+ dasd_ioctl_no_unregister(THIS_MODULE, BIODASDEERSET,
+ dasd_ioctl_set_eer);
+ dasd_ioctl_no_unregister(THIS_MODULE, BIODASDEERGET,
+ dasd_ioctl_get_eer);
+queue:
+ destroy_workqueue(dasd_eer_workqueue);
+out:
+ return rc;
+
+}
+module_init(dasd_eer_init);
+
+static void
+__exit dasd_eer_exit(void)
+{
+ dasd_unregister_eer_notifier(&dasd_eer_nb);
+ dasd_ioctl_no_unregister(THIS_MODULE, BIODASDEERSET,
+ dasd_ioctl_set_eer);
+ dasd_ioctl_no_unregister(THIS_MODULE, BIODASDEERGET,
+ dasd_ioctl_get_eer);
+ destroy_workqueue(dasd_eer_workqueue);
+
+ WARN_ON(misc_deregister(&dasd_eer_dev) != 0);
+}
+module_exit(dasd_eer_exit);
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index c20af987450..d1b08fa13fd 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -275,6 +275,34 @@ struct dasd_discipline {
extern struct dasd_discipline *dasd_diag_discipline_pointer;
+
+/*
+ * Notification numbers for extended error reporting notifications:
+ * The DASD_EER_DISABLE notification is sent before a dasd_device (and it's
+ * eer pointer) is freed. The error reporting module needs to do all necessary
+ * cleanup steps.
+ * The DASD_EER_TRIGGER notification sends the actual error reports (triggers).
+ */
+#define DASD_EER_DISABLE 0
+#define DASD_EER_TRIGGER 1
+
+/* Trigger IDs for extended error reporting DASD_EER_TRIGGER notification */
+#define DASD_EER_FATALERROR 1
+#define DASD_EER_NOPATH 2
+#define DASD_EER_STATECHANGE 3
+#define DASD_EER_PPRCSUSPEND 4
+
+/*
+ * The dasd_eer_trigger structure contains all data that we need to send
+ * along with an DASD_EER_TRIGGER notification.
+ */
+struct dasd_eer_trigger {
+ unsigned int id;
+ struct dasd_device *device;
+ struct dasd_ccw_req *cqr;
+};
+
+
struct dasd_device {
/* Block device stuff. */
struct gendisk *gdp;
@@ -288,6 +316,9 @@ struct dasd_device {
unsigned long flags; /* per device flags */
unsigned short features; /* copy of devmap-features (read-only!) */
+ /* extended error reporting stuff (eer) */
+ void *eer;
+
/* Device discipline stuff. */
struct dasd_discipline *discipline;
char *private;
@@ -488,6 +519,12 @@ int dasd_generic_set_online(struct ccw_device *, struct dasd_discipline *);
int dasd_generic_set_offline (struct ccw_device *cdev);
int dasd_generic_notify(struct ccw_device *, int);
void dasd_generic_auto_online (struct ccw_driver *);
+int dasd_register_eer_notifier(struct notifier_block *);
+int dasd_unregister_eer_notifier(struct notifier_block *);
+void dasd_write_eer_trigger(unsigned int , struct dasd_device *,
+ struct dasd_ccw_req *);
+
+
/* externals in dasd_devmap.c */
extern int dasd_max_devindex;
diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h
index 44e4b4bb1c5..3e75095f35d 100644
--- a/drivers/s390/cio/chsc.h
+++ b/drivers/s390/cio/chsc.h
@@ -68,6 +68,6 @@ extern void *chsc_get_chp_desc(struct subchannel*, int);
extern int chsc_enable_facility(int);
-#define to_channelpath(dev) container_of(dev, struct channel_path, dev)
+#define to_channelpath(device) container_of(device, struct channel_path, dev)
#endif
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 245ca99a641..c551bb84dbf 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -1245,7 +1245,7 @@ static int __init init_scsi(void)
if (error)
goto cleanup_sysctl;
- for (i = 0; i < NR_CPUS; i++)
+ for_each_cpu(i)
INIT_LIST_HEAD(&per_cpu(scsi_done_q, i));
devfs_mk_dir("scsi");
diff --git a/drivers/serial/8250_pci.c b/drivers/serial/8250_pci.c
index 2a912153321..bb9ec28ccc2 100644
--- a/drivers/serial/8250_pci.c
+++ b/drivers/serial/8250_pci.c
@@ -439,6 +439,20 @@ static int pci_siig_init(struct pci_dev *dev)
return -ENODEV;
}
+static int pci_siig_setup(struct serial_private *priv,
+ struct pciserial_board *board,
+ struct uart_port *port, int idx)
+{
+ unsigned int bar = FL_GET_BASE(board->flags) + idx, offset = 0;
+
+ if (idx > 3) {
+ bar = 4;
+ offset = (idx - 4) * 8;
+ }
+
+ return setup_port(priv, port, bar, offset, 0);
+}
+
/*
* Timedia has an explosion of boards, and to avoid the PCI table from
* growing *huge*, we use this function to collapse some 70 entries
@@ -748,7 +762,7 @@ static struct pci_serial_quirk pci_serial_quirks[] = {
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.init = pci_siig_init,
- .setup = pci_default_setup,
+ .setup = pci_siig_setup,
},
/*
* Titan cards
@@ -2141,6 +2155,15 @@ static struct pci_device_id serial_pci_tbl[] = {
{ PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850,
PCI_ANY_ID, PCI_ANY_ID, 0, 0,
pbn_b0_bt_4_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_550,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_8_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_650,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_8_921600 },
+ { PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_8S_20x_850,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+ pbn_b0_bt_8_921600 },
/*
* Computone devices submitted by Doug McNash dmcnash@computone.com
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 0d38f0f2ae2..0f4361c8466 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -98,6 +98,7 @@ config SERIAL_8250_NR_UARTS
config SERIAL_8250_RUNTIME_UARTS
int "Number of 8250/16550 serial ports to register at runtime"
depends on SERIAL_8250
+ range 0 SERIAL_8250_NR_UARTS
default "4"
help
Set this to the maximum number of serial ports you want
@@ -892,20 +893,20 @@ config SERIAL_VR41XX_CONSOLE
a console on a serial port, say Y. Otherwise, say N.
config SERIAL_JSM
- tristate "Digi International NEO PCI Support"
- depends on PCI && BROKEN
- select SERIAL_CORE
- help
- This is a driver for Digi International's Neo series
- of cards which provide multiple serial ports. You would need
- something like this to connect more than two modems to your Linux
- box, for instance in order to become a dial-in server. This driver
- supports PCI boards only.
- If you have a card like this, say Y here and read the file
- <file:Documentation/jsm.txt>.
-
- To compile this driver as a module, choose M here: the
- module will be called jsm.
+ tristate "Digi International NEO PCI Support"
+ depends on PCI
+ select SERIAL_CORE
+ help
+ This is a driver for Digi International's Neo series
+ of cards which provide multiple serial ports. You would need
+ something like this to connect more than two modems to your Linux
+ box, for instance in order to become a dial-in server. This driver
+ supports PCI boards only.
+ If you have a card like this, say Y here and read the file
+ <file:Documentation/jsm.txt>.
+
+ To compile this driver as a module, choose M here: the
+ module will be called jsm.
config SERIAL_SGI_IOC4
tristate "SGI IOC4 controller serial support"
diff --git a/drivers/serial/jsm/jsm.h b/drivers/serial/jsm/jsm.h
index 18753193f59..dfc1e86d3aa 100644
--- a/drivers/serial/jsm/jsm.h
+++ b/drivers/serial/jsm/jsm.h
@@ -380,7 +380,6 @@ struct neo_uart_struct {
extern struct uart_driver jsm_uart_driver;
extern struct board_ops jsm_neo_ops;
extern int jsm_debug;
-extern int jsm_rawreadok;
/*************************************************************************
*
diff --git a/drivers/serial/jsm/jsm_driver.c b/drivers/serial/jsm/jsm_driver.c
index 7e56c782419..b1b66e71d28 100644
--- a/drivers/serial/jsm/jsm_driver.c
+++ b/drivers/serial/jsm/jsm_driver.c
@@ -49,11 +49,8 @@ struct uart_driver jsm_uart_driver = {
};
int jsm_debug;
-int jsm_rawreadok;
module_param(jsm_debug, int, 0);
-module_param(jsm_rawreadok, int, 0);
MODULE_PARM_DESC(jsm_debug, "Driver debugging level");
-MODULE_PARM_DESC(jsm_rawreadok, "Bypass flip buffers on input");
static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
diff --git a/drivers/serial/jsm/jsm_tty.c b/drivers/serial/jsm/jsm_tty.c
index 6fa0d62d6f6..4d48b625cd3 100644
--- a/drivers/serial/jsm/jsm_tty.c
+++ b/drivers/serial/jsm/jsm_tty.c
@@ -20,8 +20,10 @@
*
* Contact Information:
* Scott H Kilau <Scott_Kilau@digi.com>
- * Wendy Xiong <wendyx@us.ltcfwd.linux.ibm.com>
- *
+ * Ananda Venkatarman <mansarov@us.ibm.com>
+ * Modifications:
+ * 01/19/06: changed jsm_input routine to use the dynamically allocated
+ * tty_buffer changes. Contributors: Scott Kilau and Ananda V.
***********************************************************************/
#include <linux/tty.h>
#include <linux/tty_flip.h>
@@ -497,16 +499,15 @@ void jsm_input(struct jsm_channel *ch)
{
struct jsm_board *bd;
struct tty_struct *tp;
+ struct tty_ldisc *ld;
u32 rmask;
u16 head;
u16 tail;
int data_len;
unsigned long lock_flags;
- int flip_len;
+ int flip_len = 0;
int len = 0;
int n = 0;
- char *buf = NULL;
- char *buf2 = NULL;
int s = 0;
int i = 0;
@@ -574,56 +575,50 @@ void jsm_input(struct jsm_channel *ch)
/*
* If the rxbuf is empty and we are not throttled, put as much
- * as we can directly into the linux TTY flip buffer.
- * The jsm_rawreadok case takes advantage of carnal knowledge that
- * the char_buf and the flag_buf are next to each other and
- * are each of (2 * TTY_FLIPBUF_SIZE) size.
+ * as we can directly into the linux TTY buffer.
*
- * NOTE: if(!tty->real_raw), the call to ldisc.receive_buf
- *actually still uses the flag buffer, so you can't
- *use it for input data
*/
- if (jsm_rawreadok) {
- if (tp->real_raw)
- flip_len = MYFLIPLEN;
- else
- flip_len = 2 * TTY_FLIPBUF_SIZE;
- } else
- flip_len = TTY_FLIPBUF_SIZE - tp->flip.count;
+ flip_len = TTY_FLIPBUF_SIZE;
len = min(data_len, flip_len);
len = min(len, (N_TTY_BUF_SIZE - 1) - tp->read_cnt);
+ ld = tty_ldisc_ref(tp);
- if (len <= 0) {
- spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
- jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "jsm_input 1\n");
- return;
- }
+ /*
+ * If the DONT_FLIP flag is on, don't flush our buffer, and act
+ * like the ld doesn't have any space to put the data right now.
+ */
+ if (test_bit(TTY_DONT_FLIP, &tp->flags))
+ len = 0;
/*
- * If we're bypassing flip buffers on rx, we can blast it
- * right into the beginning of the buffer.
+ * If we were unable to get a reference to the ld,
+ * don't flush our buffer, and act like the ld doesn't
+ * have any space to put the data right now.
*/
- if (jsm_rawreadok) {
- if (tp->real_raw) {
- if (ch->ch_flags & CH_FLIPBUF_IN_USE) {
- jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
- "JSM - FLIPBUF in use. delaying input\n");
- spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
- return;
- }
- ch->ch_flags |= CH_FLIPBUF_IN_USE;
- buf = ch->ch_bd->flipbuf;
- buf2 = NULL;
- } else {
- buf = tp->flip.char_buf;
- buf2 = tp->flip.flag_buf;
- }
+ if (!ld) {
+ len = 0;
} else {
- buf = tp->flip.char_buf_ptr;
- buf2 = tp->flip.flag_buf_ptr;
+ /*
+ * If ld doesn't have a pointer to a receive_buf function,
+ * flush the data, then act like the ld doesn't have any
+ * space to put the data right now.
+ */
+ if (!ld->receive_buf) {
+ ch->ch_r_head = ch->ch_r_tail;
+ len = 0;
+ }
}
+ if (len <= 0) {
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+ jsm_printk(READ, INFO, &ch->ch_bd->pci_dev, "jsm_input 1\n");
+ if (ld)
+ tty_ldisc_deref(ld);
+ return;
+ }
+
+ len = tty_buffer_request_room(tp, len);
n = len;
/*
@@ -638,121 +633,47 @@ void jsm_input(struct jsm_channel *ch)
if (s <= 0)
break;
- memcpy(buf, ch->ch_rqueue + tail, s);
-
- /* buf2 is only set when port isn't raw */
- if (buf2)
- memcpy(buf2, ch->ch_equeue + tail, s);
-
- tail += s;
- buf += s;
- if (buf2)
- buf2 += s;
- n -= s;
- /* Flip queue if needed */
- tail &= rmask;
- }
+ /*
+ * If conditions are such that ld needs to see all
+ * UART errors, we will have to walk each character
+ * and error byte and send them to the buffer one at
+ * a time.
+ */
- /*
- * In high performance mode, we don't have to update
- * flag_buf or any of the counts or pointers into flip buf.
- */
- if (!jsm_rawreadok) {
if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
- for (i = 0; i < len; i++) {
+ for (i = 0; i < s; i++) {
/*
* Give the Linux ld the flags in the
* format it likes.
*/
- if (tp->flip.flag_buf_ptr[i] & UART_LSR_BI)
- tp->flip.flag_buf_ptr[i] = TTY_BREAK;
- else if (tp->flip.flag_buf_ptr[i] & UART_LSR_PE)
- tp->flip.flag_buf_ptr[i] = TTY_PARITY;
- else if (tp->flip.flag_buf_ptr[i] & UART_LSR_FE)
- tp->flip.flag_buf_ptr[i] = TTY_FRAME;
+ if (*(ch->ch_equeue +tail +i) & UART_LSR_BI)
+ tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_BREAK);
+ else if (*(ch->ch_equeue +tail +i) & UART_LSR_PE)
+ tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_PARITY);
+ else if (*(ch->ch_equeue +tail +i) & UART_LSR_FE)
+ tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_FRAME);
else
- tp->flip.flag_buf_ptr[i] = TTY_NORMAL;
+ tty_insert_flip_char(tp, *(ch->ch_rqueue +tail +i), TTY_NORMAL);
}
} else {
- memset(tp->flip.flag_buf_ptr, 0, len);
+ tty_insert_flip_string(tp, ch->ch_rqueue + tail, s) ;
}
-
- tp->flip.char_buf_ptr += len;
- tp->flip.flag_buf_ptr += len;
- tp->flip.count += len;
- }
- else if (!tp->real_raw) {
- if (I_PARMRK(tp) || I_BRKINT(tp) || I_INPCK(tp)) {
- for (i = 0; i < len; i++) {
- /*
- * Give the Linux ld the flags in the
- * format it likes.
- */
- if (tp->flip.flag_buf_ptr[i] & UART_LSR_BI)
- tp->flip.flag_buf_ptr[i] = TTY_BREAK;
- else if (tp->flip.flag_buf_ptr[i] & UART_LSR_PE)
- tp->flip.flag_buf_ptr[i] = TTY_PARITY;
- else if (tp->flip.flag_buf_ptr[i] & UART_LSR_FE)
- tp->flip.flag_buf_ptr[i] = TTY_FRAME;
- else
- tp->flip.flag_buf_ptr[i] = TTY_NORMAL;
- }
- } else
- memset(tp->flip.flag_buf, 0, len);
+ tail += s;
+ n -= s;
+ /* Flip queue if needed */
+ tail &= rmask;
}
- /*
- * If we're doing raw reads, jam it right into the
- * line disc bypassing the flip buffers.
- */
- if (jsm_rawreadok) {
- if (tp->real_raw) {
- ch->ch_r_tail = tail & rmask;
- ch->ch_e_tail = tail & rmask;
-
- jsm_check_queue_flow_control(ch);
-
- /* !!! WE *MUST* LET GO OF ALL LOCKS BEFORE CALLING RECEIVE BUF !!! */
+ ch->ch_r_tail = tail & rmask;
+ ch->ch_e_tail = tail & rmask;
+ jsm_check_queue_flow_control(ch);
+ spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
- spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
+ /* Tell the tty layer its okay to "eat" the data now */
+ tty_flip_buffer_push(tp);
- jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
- "jsm_input. %d real_raw len:%d calling receive_buf for board %d\n",
- __LINE__, len, ch->ch_bd->boardnum);
- tp->ldisc.receive_buf(tp, ch->ch_bd->flipbuf, NULL, len);
-
- /* Allow use of channel flip buffer again */
- spin_lock_irqsave(&ch->ch_lock, lock_flags);
- ch->ch_flags &= ~CH_FLIPBUF_IN_USE;
- spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-
- } else {
- ch->ch_r_tail = tail & rmask;
- ch->ch_e_tail = tail & rmask;
-
- jsm_check_queue_flow_control(ch);
-
- /* !!! WE *MUST* LET GO OF ALL LOCKS BEFORE CALLING RECEIVE BUF !!! */
- spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-
- jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
- "jsm_input. %d not real_raw len:%d calling receive_buf for board %d\n",
- __LINE__, len, ch->ch_bd->boardnum);
-
- tp->ldisc.receive_buf(tp, tp->flip.char_buf, tp->flip.flag_buf, len);
- }
- } else {
- ch->ch_r_tail = tail & rmask;
- ch->ch_e_tail = tail & rmask;
-
- jsm_check_queue_flow_control(ch);
-
- spin_unlock_irqrestore(&ch->ch_lock, lock_flags);
-
- jsm_printk(READ, INFO, &ch->ch_bd->pci_dev,
- "jsm_input. %d not jsm_read raw okay scheduling flip\n", __LINE__);
- tty_schedule_flip(tp);
- }
+ if (ld)
+ tty_ldisc_deref(ld);
jsm_printk(IOCTL, INFO, &ch->ch_bd->pci_dev, "finish\n");
}
diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c
index d957a3a9edf..0ef648fa4b2 100644
--- a/drivers/serial/mcfserial.c
+++ b/drivers/serial/mcfserial.c
@@ -350,8 +350,7 @@ static inline void receive_chars(struct mcf_serial *info)
}
tty_insert_flip_char(tty, ch, flag);
}
-
- schedule_work(&tty->flip.work);
+ tty_flip_buffer_push(tty);
return;
}
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 0717abfdae0..95fb4939c67 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -2237,7 +2237,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
* If this port is a console, then the spinlock is already
* initialised.
*/
- if (!uart_console(port))
+ if (!(uart_console(port) && (port->cons->flags & CON_ENABLED)))
spin_lock_init(&port->lock);
uart_configure_port(drv, state, port);
diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c
index f6704688ee8..5578a9dd04e 100644
--- a/drivers/telephony/ixj.c
+++ b/drivers/telephony/ixj.c
@@ -3558,10 +3558,16 @@ static void ixj_write_frame(IXJ *j)
}
/* Add word 0 to G.729 frames for the 8021. Right now we don't do VAD/CNG */
if (j->play_codec == G729 && (cnt == 0 || cnt == 10 || cnt == 20)) {
- if(j->write_buffer_rp + cnt == 0 && j->write_buffer_rp + cnt + 1 == 0 && j->write_buffer_rp + cnt + 2 == 0 &&
- j->write_buffer_rp + cnt + 3 == 0 && j->write_buffer_rp + cnt + 4 == 0 && j->write_buffer_rp + cnt + 5 == 0 &&
- j->write_buffer_rp + cnt + 6 == 0 && j->write_buffer_rp + cnt + 7 == 0 && j->write_buffer_rp + cnt + 8 == 0 &&
- j->write_buffer_rp + cnt + 9 == 0) {
+ if (j->write_buffer_rp[cnt] == 0 &&
+ j->write_buffer_rp[cnt + 1] == 0 &&
+ j->write_buffer_rp[cnt + 2] == 0 &&
+ j->write_buffer_rp[cnt + 3] == 0 &&
+ j->write_buffer_rp[cnt + 4] == 0 &&
+ j->write_buffer_rp[cnt + 5] == 0 &&
+ j->write_buffer_rp[cnt + 6] == 0 &&
+ j->write_buffer_rp[cnt + 7] == 0 &&
+ j->write_buffer_rp[cnt + 8] == 0 &&
+ j->write_buffer_rp[cnt + 9] == 0) {
/* someone is trying to write silence lets make this a type 0 frame. */
outb_p(0x00, j->DSPbase + 0x0C);
outb_p(0x00, j->DSPbase + 0x0D);
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 076462c8ba2..dce9d987f0f 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -378,7 +378,7 @@ const struct usb_device_id *usb_match_id(struct usb_interface *interface,
return NULL;
}
-EXPORT_SYMBOL_GPL(usb_match_id);
+EXPORT_SYMBOL(usb_match_id);
int usb_device_match(struct device *dev, struct device_driver *drv)
{
@@ -446,7 +446,7 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner)
return retval;
}
-EXPORT_SYMBOL_GPL(usb_register_driver);
+EXPORT_SYMBOL(usb_register_driver);
/**
* usb_deregister - unregister a USB driver
@@ -469,4 +469,4 @@ void usb_deregister(struct usb_driver *driver)
usbfs_update_special();
}
-EXPORT_SYMBOL_GPL(usb_deregister);
+EXPORT_SYMBOL(usb_deregister);
diff --git a/drivers/video/console/sticore.c b/drivers/video/console/sticore.c
index a7bcd17112c..0339f5640a7 100644
--- a/drivers/video/console/sticore.c
+++ b/drivers/video/console/sticore.c
@@ -30,10 +30,11 @@
#define STI_DRIVERVERSION "Version 0.9a"
-struct sti_struct *default_sti;
+struct sti_struct *default_sti __read_mostly;
-static int num_sti_roms; /* # of STI ROMS found */
-static struct sti_struct *sti_roms[MAX_STI_ROMS]; /* ptr to each sti_struct */
+/* number of STI ROMS found and their ptrs to each struct */
+static int num_sti_roms __read_mostly;
+static struct sti_struct *sti_roms[MAX_STI_ROMS] __read_mostly;
/* The colour indices used by STI are
@@ -266,7 +267,7 @@ sti_rom_copy(unsigned long base, unsigned long count, void *dest)
-static char default_sti_path[21];
+static char default_sti_path[21] __read_mostly;
#ifndef MODULE
static int __init sti_setup(char *str)
@@ -414,10 +415,10 @@ sti_init_glob_cfg(struct sti_struct *sti,
if (!sti->sti_mem_request)
sti->sti_mem_request = 256; /* STI default */
- glob_cfg = kmalloc(sizeof(*sti->glob_cfg), GFP_KERNEL);
- glob_cfg_ext = kmalloc(sizeof(*glob_cfg_ext), GFP_KERNEL);
- save_addr = kmalloc(save_addr_size, GFP_KERNEL);
- sti_mem_addr = kmalloc(sti->sti_mem_request, GFP_KERNEL);
+ glob_cfg = kzalloc(sizeof(*sti->glob_cfg), GFP_KERNEL);
+ glob_cfg_ext = kzalloc(sizeof(*glob_cfg_ext), GFP_KERNEL);
+ save_addr = kzalloc(save_addr_size, GFP_KERNEL);
+ sti_mem_addr = kzalloc(sti->sti_mem_request, GFP_KERNEL);
if (!(glob_cfg && glob_cfg_ext && save_addr && sti_mem_addr)) {
kfree(glob_cfg);
@@ -427,11 +428,6 @@ sti_init_glob_cfg(struct sti_struct *sti,
return -ENOMEM;
}
- memset(glob_cfg, 0, sizeof(*glob_cfg));
- memset(glob_cfg_ext, 0, sizeof(*glob_cfg_ext));
- memset(save_addr, 0, save_addr_size);
- memset(sti_mem_addr, 0, sti->sti_mem_request);
-
glob_cfg->ext_ptr = STI_PTR(glob_cfg_ext);
glob_cfg->save_addr = STI_PTR(save_addr);
for (i=0; i<8; i++) {
@@ -502,9 +498,9 @@ sti_init_glob_cfg(struct sti_struct *sti,
#ifdef CONFIG_FB
struct sti_cooked_font * __init
-sti_select_fbfont( struct sti_cooked_rom *cooked_rom, char *fbfont_name )
+sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name)
{
- struct font_desc *fbfont;
+ const struct font_desc *fbfont;
unsigned int size, bpc;
void *dest;
struct sti_rom_font *nf;
@@ -525,10 +521,9 @@ sti_select_fbfont( struct sti_cooked_rom *cooked_rom, char *fbfont_name )
size = bpc * 256;
size += sizeof(struct sti_rom_font);
- nf = kmalloc(size, GFP_KERNEL);
+ nf = kzalloc(size, GFP_KERNEL);
if (!nf)
return NULL;
- memset(nf, 0, size);
nf->first_char = 0;
nf->last_char = 255;
@@ -544,7 +539,7 @@ sti_select_fbfont( struct sti_cooked_rom *cooked_rom, char *fbfont_name )
dest += sizeof(struct sti_rom_font);
memcpy(dest, fbfont->data, bpc*256);
- cooked_font = kmalloc(sizeof(*cooked_font), GFP_KERNEL);
+ cooked_font = kzalloc(sizeof(*cooked_font), GFP_KERNEL);
if (!cooked_font) {
kfree(nf);
return NULL;
@@ -559,7 +554,7 @@ sti_select_fbfont( struct sti_cooked_rom *cooked_rom, char *fbfont_name )
}
#else
struct sti_cooked_font * __init
-sti_select_fbfont(struct sti_cooked_rom *cooked_rom, char *fbfont_name)
+sti_select_fbfont(struct sti_cooked_rom *cooked_rom, const char *fbfont_name)
{
return NULL;
}
@@ -617,7 +612,7 @@ sti_cook_fonts(struct sti_cooked_rom *cooked_rom,
struct sti_rom_font *raw_font, *font_start;
struct sti_cooked_font *cooked_font;
- cooked_font = kmalloc(sizeof(*cooked_font), GFP_KERNEL);
+ cooked_font = kzalloc(sizeof(*cooked_font), GFP_KERNEL);
if (!cooked_font)
return 0;
@@ -631,7 +626,7 @@ sti_cook_fonts(struct sti_cooked_rom *cooked_rom,
while (raw_font->next_font) {
raw_font = ((void *)font_start) + (raw_font->next_font);
- cooked_font->next_font = kmalloc(sizeof(*cooked_font), GFP_KERNEL);
+ cooked_font->next_font = kzalloc(sizeof(*cooked_font), GFP_KERNEL);
if (!cooked_font->next_font)
return 1;
@@ -668,10 +663,9 @@ sti_bmode_font_raw(struct sti_cooked_font *f)
unsigned char *n, *p, *q;
int size = f->raw->bytes_per_char*256+sizeof(struct sti_rom_font);
- n = kmalloc (4*size, GFP_KERNEL);
+ n = kzalloc (4*size, GFP_KERNEL);
if (!n)
return NULL;
- memset (n, 0, 4*size);
p = n + 3;
q = (unsigned char *)f->raw;
while (size--) {
@@ -816,13 +810,12 @@ sti_try_rom_generic(unsigned long address, unsigned long hpa, struct pci_dev *pd
return NULL;
}
- sti = kmalloc(sizeof(*sti), GFP_KERNEL);
+ sti = kzalloc(sizeof(*sti), GFP_KERNEL);
if (!sti) {
printk(KERN_ERR "Not enough memory !\n");
return NULL;
}
- memset(sti, 0, sizeof(*sti));
spin_lock_init(&sti->lock);
test_rom:
@@ -1035,7 +1028,7 @@ static struct parisc_driver pa_sti_driver = {
* sti_init_roms() - detects all STI ROMs and stores them in sti_roms[]
*/
-static int sticore_initialized;
+static int sticore_initialized __read_mostly;
static void __init sti_init_roms(void)
{
diff --git a/fs/9p/conv.c b/fs/9p/conv.c
index 32a9f99154e..bf1f1006796 100644
--- a/fs/9p/conv.c
+++ b/fs/9p/conv.c
@@ -116,13 +116,19 @@ static void buf_put_int64(struct cbuf *buf, u64 val)
}
}
-static void buf_put_stringn(struct cbuf *buf, const char *s, u16 slen)
+static char *buf_put_stringn(struct cbuf *buf, const char *s, u16 slen)
{
+ char *ret;
+
+ ret = NULL;
if (buf_check_size(buf, slen + 2)) {
buf_put_int16(buf, slen);
+ ret = buf->p;
memcpy(buf->p, s, slen);
buf->p += slen;
}
+
+ return ret;
}
static inline void buf_put_string(struct cbuf *buf, const char *s)
@@ -430,15 +436,19 @@ static inline void v9fs_put_int64(struct cbuf *bufp, u64 val, u64 * p)
static void
v9fs_put_str(struct cbuf *bufp, char *data, struct v9fs_str *str)
{
- if (data) {
- str->len = strlen(data);
- str->str = bufp->p;
- } else {
- str->len = 0;
- str->str = NULL;
- }
+ int len;
+ char *s;
+
+ if (data)
+ len = strlen(data);
+ else
+ len = 0;
- buf_put_stringn(bufp, data, str->len);
+ s = buf_put_stringn(bufp, data, len);
+ if (str) {
+ str->len = len;
+ str->str = s;
+ }
}
static int
diff --git a/fs/9p/mux.c b/fs/9p/mux.c
index 945cb368d45..ea1134eb47c 100644
--- a/fs/9p/mux.c
+++ b/fs/9p/mux.c
@@ -471,10 +471,13 @@ static void v9fs_write_work(void *a)
}
spin_lock(&m->lock);
- req =
- list_entry(m->unsent_req_list.next, struct v9fs_req,
+again:
+ req = list_entry(m->unsent_req_list.next, struct v9fs_req,
req_list);
list_move_tail(&req->req_list, &m->req_list);
+ if (req->err == ERREQFLUSH)
+ goto again;
+
m->wbuf = req->tcall->sdata;
m->wsize = req->tcall->size;
m->wpos = 0;
@@ -525,7 +528,7 @@ static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req)
struct v9fs_str *ename;
tag = req->tag;
- if (req->rcall->id == RERROR && !req->err) {
+ if (!req->err && req->rcall->id == RERROR) {
ecode = req->rcall->params.rerror.errno;
ename = &req->rcall->params.rerror.error;
@@ -551,7 +554,10 @@ static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req)
req->err = -EIO;
}
- if (req->cb && req->err != ERREQFLUSH) {
+ if (req->err == ERREQFLUSH)
+ return;
+
+ if (req->cb) {
dprintk(DEBUG_MUX, "calling callback tcall %p rcall %p\n",
req->tcall, req->rcall);
@@ -812,6 +818,7 @@ v9fs_mux_rpc_cb(void *a, struct v9fs_fcall *tc, struct v9fs_fcall *rc, int err)
struct v9fs_mux_rpc *r;
if (err == ERREQFLUSH) {
+ kfree(rc);
dprintk(DEBUG_MUX, "err req flush\n");
return;
}
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 91f552454c7..63e5b0398e8 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -886,8 +886,8 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
}
/* copy extension buffer into buffer */
- if (fcall->params.rstat.stat.extension.len < buflen)
- buflen = fcall->params.rstat.stat.extension.len;
+ if (fcall->params.rstat.stat.extension.len+1 < buflen)
+ buflen = fcall->params.rstat.stat.extension.len + 1;
memcpy(buffer, fcall->params.rstat.stat.extension.str, buflen - 1);
buffer[buflen-1] = 0;
@@ -951,7 +951,7 @@ static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd)
if (!link)
link = ERR_PTR(-ENOMEM);
else {
- len = v9fs_readlink(dentry, link, strlen(link));
+ len = v9fs_readlink(dentry, link, PATH_MAX);
if (len < 0) {
__putname(link);
diff --git a/fs/Kconfig b/fs/Kconfig
index 93b5dc4082f..e9749b0eecd 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -883,8 +883,6 @@ config CONFIGFS_FS
Both sysfs and configfs can and should exist together on the
same system. One is not a replacement for the other.
- If unsure, say N.
-
endmenu
menu "Miscellaneous filesystems"
diff --git a/fs/buffer.c b/fs/buffer.c
index 5e4a90ee103..62cfd17dc5f 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -2867,22 +2867,22 @@ void ll_rw_block(int rw, int nr, struct buffer_head *bhs[])
else if (test_set_buffer_locked(bh))
continue;
- get_bh(bh);
if (rw == WRITE || rw == SWRITE) {
if (test_clear_buffer_dirty(bh)) {
bh->b_end_io = end_buffer_write_sync;
+ get_bh(bh);
submit_bh(WRITE, bh);
continue;
}
} else {
if (!buffer_uptodate(bh)) {
bh->b_end_io = end_buffer_read_sync;
+ get_bh(bh);
submit_bh(rw, bh);
continue;
}
}
unlock_buffer(bh);
- put_bh(bh);
}
}
diff --git a/fs/configfs/configfs_internal.h b/fs/configfs/configfs_internal.h
index 8899d9c5f6b..f70e46951b3 100644
--- a/fs/configfs/configfs_internal.h
+++ b/fs/configfs/configfs_internal.h
@@ -36,6 +36,7 @@ struct configfs_dirent {
int s_type;
umode_t s_mode;
struct dentry * s_dentry;
+ struct iattr * s_iattr;
};
#define CONFIGFS_ROOT 0x0001
@@ -48,10 +49,11 @@ struct configfs_dirent {
#define CONFIGFS_NOT_PINNED (CONFIGFS_ITEM_ATTR)
extern struct vfsmount * configfs_mount;
+extern kmem_cache_t *configfs_dir_cachep;
extern int configfs_is_root(struct config_item *item);
-extern struct inode * configfs_new_inode(mode_t mode);
+extern struct inode * configfs_new_inode(mode_t mode, struct configfs_dirent *);
extern int configfs_create(struct dentry *, int mode, int (*init)(struct inode *));
extern int configfs_create_file(struct config_item *, const struct configfs_attribute *);
@@ -63,6 +65,7 @@ extern void configfs_hash_and_remove(struct dentry * dir, const char * name);
extern const unsigned char * configfs_get_name(struct configfs_dirent *sd);
extern void configfs_drop_dentry(struct configfs_dirent *sd, struct dentry *parent);
+extern int configfs_setattr(struct dentry *dentry, struct iattr *iattr);
extern int configfs_pin_fs(void);
extern void configfs_release_fs(void);
@@ -120,8 +123,10 @@ static inline struct config_item *configfs_get_config_item(struct dentry *dentry
static inline void release_configfs_dirent(struct configfs_dirent * sd)
{
- if (!(sd->s_type & CONFIGFS_ROOT))
- kfree(sd);
+ if (!(sd->s_type & CONFIGFS_ROOT)) {
+ kfree(sd->s_iattr);
+ kmem_cache_free(configfs_dir_cachep, sd);
+ }
}
static inline struct configfs_dirent * configfs_get(struct configfs_dirent * sd)
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index b668ec61527..ca60e3abef4 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -72,7 +72,7 @@ static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent * pare
{
struct configfs_dirent * sd;
- sd = kmalloc(sizeof(*sd), GFP_KERNEL);
+ sd = kmem_cache_alloc(configfs_dir_cachep, GFP_KERNEL);
if (!sd)
return NULL;
@@ -136,13 +136,19 @@ static int create_dir(struct config_item * k, struct dentry * p,
int error;
umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
- error = configfs_create(d, mode, init_dir);
+ error = configfs_make_dirent(p->d_fsdata, d, k, mode,
+ CONFIGFS_DIR);
if (!error) {
- error = configfs_make_dirent(p->d_fsdata, d, k, mode,
- CONFIGFS_DIR);
+ error = configfs_create(d, mode, init_dir);
if (!error) {
p->d_inode->i_nlink++;
(d)->d_op = &configfs_dentry_ops;
+ } else {
+ struct configfs_dirent *sd = d->d_fsdata;
+ if (sd) {
+ list_del_init(&sd->s_sibling);
+ configfs_put(sd);
+ }
}
}
return error;
@@ -182,12 +188,19 @@ int configfs_create_link(struct configfs_symlink *sl,
int err = 0;
umode_t mode = S_IFLNK | S_IRWXUGO;
- err = configfs_create(dentry, mode, init_symlink);
+ err = configfs_make_dirent(parent->d_fsdata, dentry, sl, mode,
+ CONFIGFS_ITEM_LINK);
if (!err) {
- err = configfs_make_dirent(parent->d_fsdata, dentry, sl,
- mode, CONFIGFS_ITEM_LINK);
+ err = configfs_create(dentry, mode, init_symlink);
if (!err)
dentry->d_op = &configfs_dentry_ops;
+ else {
+ struct configfs_dirent *sd = dentry->d_fsdata;
+ if (sd) {
+ list_del_init(&sd->s_sibling);
+ configfs_put(sd);
+ }
+ }
}
return err;
}
@@ -241,13 +254,15 @@ static int configfs_attach_attr(struct configfs_dirent * sd, struct dentry * den
struct configfs_attribute * attr = sd->s_element;
int error;
+ dentry->d_fsdata = configfs_get(sd);
+ sd->s_dentry = dentry;
error = configfs_create(dentry, (attr->ca_mode & S_IALLUGO) | S_IFREG, init_file);
- if (error)
+ if (error) {
+ configfs_put(sd);
return error;
+ }
dentry->d_op = &configfs_dentry_ops;
- dentry->d_fsdata = configfs_get(sd);
- sd->s_dentry = dentry;
d_rehash(dentry);
return 0;
@@ -839,6 +854,7 @@ struct inode_operations configfs_dir_inode_operations = {
.symlink = configfs_symlink,
.unlink = configfs_unlink,
.lookup = configfs_lookup,
+ .setattr = configfs_setattr,
};
#if 0
diff --git a/fs/configfs/file.c b/fs/configfs/file.c
index c26cd61f13a..3921920d871 100644
--- a/fs/configfs/file.c
+++ b/fs/configfs/file.c
@@ -26,7 +26,6 @@
#include <linux/fs.h>
#include <linux/module.h>
-#include <linux/dnotify.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
@@ -150,7 +149,7 @@ out:
/**
* fill_write_buffer - copy buffer from userspace.
* @buffer: data buffer for file.
- * @userbuf: data from user.
+ * @buf: data from user.
* @count: number of bytes in @userbuf.
*
* Allocate @buffer->page if it hasn't been already, then
@@ -177,8 +176,9 @@ fill_write_buffer(struct configfs_buffer * buffer, const char __user * buf, size
/**
* flush_write_buffer - push buffer to config_item.
- * @file: file pointer.
+ * @dentry: dentry to the attribute
* @buffer: data buffer for file.
+ * @count: number of bytes
*
* Get the correct pointers for the config_item and the attribute we're
* dealing with, then call the store() method for the attribute,
@@ -217,15 +217,16 @@ static ssize_t
configfs_write_file(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
struct configfs_buffer * buffer = file->private_data;
+ ssize_t len;
down(&buffer->sem);
- count = fill_write_buffer(buffer,buf,count);
- if (count > 0)
- count = flush_write_buffer(file->f_dentry,buffer,count);
- if (count > 0)
- *ppos += count;
+ len = fill_write_buffer(buffer, buf, count);
+ if (len > 0)
+ len = flush_write_buffer(file->f_dentry, buffer, count);
+ if (len > 0)
+ *ppos += len;
up(&buffer->sem);
- return count;
+ return len;
}
static int check_perm(struct inode * inode, struct file * file)
diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c
index 6577c588de9..c153bd9534c 100644
--- a/fs/configfs/inode.c
+++ b/fs/configfs/inode.c
@@ -31,6 +31,7 @@
#include <linux/pagemap.h>
#include <linux/namei.h>
#include <linux/backing-dev.h>
+#include <linux/capability.h>
#include <linux/configfs.h>
#include "configfs_internal.h"
@@ -48,18 +49,107 @@ static struct backing_dev_info configfs_backing_dev_info = {
.capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,
};
-struct inode * configfs_new_inode(mode_t mode)
+static struct inode_operations configfs_inode_operations ={
+ .setattr = configfs_setattr,
+};
+
+int configfs_setattr(struct dentry * dentry, struct iattr * iattr)
+{
+ struct inode * inode = dentry->d_inode;
+ struct configfs_dirent * sd = dentry->d_fsdata;
+ struct iattr * sd_iattr;
+ unsigned int ia_valid = iattr->ia_valid;
+ int error;
+
+ if (!sd)
+ return -EINVAL;
+
+ sd_iattr = sd->s_iattr;
+
+ error = inode_change_ok(inode, iattr);
+ if (error)
+ return error;
+
+ error = inode_setattr(inode, iattr);
+ if (error)
+ return error;
+
+ if (!sd_iattr) {
+ /* setting attributes for the first time, allocate now */
+ sd_iattr = kmalloc(sizeof(struct iattr), GFP_KERNEL);
+ if (!sd_iattr)
+ return -ENOMEM;
+ /* assign default attributes */
+ memset(sd_iattr, 0, sizeof(struct iattr));
+ sd_iattr->ia_mode = sd->s_mode;
+ sd_iattr->ia_uid = 0;
+ sd_iattr->ia_gid = 0;
+ sd_iattr->ia_atime = sd_iattr->ia_mtime = sd_iattr->ia_ctime = CURRENT_TIME;
+ sd->s_iattr = sd_iattr;
+ }
+
+ /* attributes were changed atleast once in past */
+
+ if (ia_valid & ATTR_UID)
+ sd_iattr->ia_uid = iattr->ia_uid;
+ if (ia_valid & ATTR_GID)
+ sd_iattr->ia_gid = iattr->ia_gid;
+ if (ia_valid & ATTR_ATIME)
+ sd_iattr->ia_atime = timespec_trunc(iattr->ia_atime,
+ inode->i_sb->s_time_gran);
+ if (ia_valid & ATTR_MTIME)
+ sd_iattr->ia_mtime = timespec_trunc(iattr->ia_mtime,
+ inode->i_sb->s_time_gran);
+ if (ia_valid & ATTR_CTIME)
+ sd_iattr->ia_ctime = timespec_trunc(iattr->ia_ctime,
+ inode->i_sb->s_time_gran);
+ if (ia_valid & ATTR_MODE) {
+ umode_t mode = iattr->ia_mode;
+
+ if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
+ mode &= ~S_ISGID;
+ sd_iattr->ia_mode = sd->s_mode = mode;
+ }
+
+ return error;
+}
+
+static inline void set_default_inode_attr(struct inode * inode, mode_t mode)
+{
+ inode->i_mode = mode;
+ inode->i_uid = 0;
+ inode->i_gid = 0;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+}
+
+static inline void set_inode_attr(struct inode * inode, struct iattr * iattr)
+{
+ inode->i_mode = iattr->ia_mode;
+ inode->i_uid = iattr->ia_uid;
+ inode->i_gid = iattr->ia_gid;
+ inode->i_atime = iattr->ia_atime;
+ inode->i_mtime = iattr->ia_mtime;
+ inode->i_ctime = iattr->ia_ctime;
+}
+
+struct inode * configfs_new_inode(mode_t mode, struct configfs_dirent * sd)
{
struct inode * inode = new_inode(configfs_sb);
if (inode) {
- inode->i_mode = mode;
- inode->i_uid = 0;
- inode->i_gid = 0;
inode->i_blksize = PAGE_CACHE_SIZE;
inode->i_blocks = 0;
- inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_mapping->a_ops = &configfs_aops;
inode->i_mapping->backing_dev_info = &configfs_backing_dev_info;
+ inode->i_op = &configfs_inode_operations;
+
+ if (sd->s_iattr) {
+ /* sysfs_dirent has non-default attributes
+ * get them for the new inode from persistent copy
+ * in sysfs_dirent
+ */
+ set_inode_attr(inode, sd->s_iattr);
+ } else
+ set_default_inode_attr(inode, mode);
}
return inode;
}
@@ -70,7 +160,8 @@ int configfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *
struct inode * inode = NULL;
if (dentry) {
if (!dentry->d_inode) {
- if ((inode = configfs_new_inode(mode))) {
+ struct configfs_dirent *sd = dentry->d_fsdata;
+ if ((inode = configfs_new_inode(mode, sd))) {
if (dentry->d_parent && dentry->d_parent->d_inode) {
struct inode *p_inode = dentry->d_parent->d_inode;
p_inode->i_mtime = p_inode->i_ctime = CURRENT_TIME;
@@ -103,10 +194,9 @@ int configfs_create(struct dentry * dentry, int mode, int (*init)(struct inode *
*/
const unsigned char * configfs_get_name(struct configfs_dirent *sd)
{
- struct attribute * attr;
+ struct configfs_attribute *attr;
- if (!sd || !sd->s_element)
- BUG();
+ BUG_ON(!sd || !sd->s_element);
/* These always have a dentry, so use that */
if (sd->s_type & (CONFIGFS_DIR | CONFIGFS_ITEM_LINK))
@@ -114,7 +204,7 @@ const unsigned char * configfs_get_name(struct configfs_dirent *sd)
if (sd->s_type & CONFIGFS_ITEM_ATTR) {
attr = sd->s_element;
- return attr->name;
+ return attr->ca_name;
}
return NULL;
}
@@ -130,13 +220,17 @@ void configfs_drop_dentry(struct configfs_dirent * sd, struct dentry * parent)
if (dentry) {
spin_lock(&dcache_lock);
+ spin_lock(&dentry->d_lock);
if (!(d_unhashed(dentry) && dentry->d_inode)) {
dget_locked(dentry);
__d_drop(dentry);
+ spin_unlock(&dentry->d_lock);
spin_unlock(&dcache_lock);
simple_unlink(parent->d_inode, dentry);
- } else
+ } else {
+ spin_unlock(&dentry->d_lock);
spin_unlock(&dcache_lock);
+ }
}
}
@@ -145,6 +239,10 @@ void configfs_hash_and_remove(struct dentry * dir, const char * name)
struct configfs_dirent * sd;
struct configfs_dirent * parent_sd = dir->d_fsdata;
+ if (dir->d_inode == NULL)
+ /* no inode means this hasn't been made visible yet */
+ return;
+
mutex_lock(&dir->d_inode->i_mutex);
list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
if (!sd->s_element)
diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c
index 1a2f6f6a4d9..f920d30478e 100644
--- a/fs/configfs/mount.c
+++ b/fs/configfs/mount.c
@@ -38,6 +38,7 @@
struct vfsmount * configfs_mount = NULL;
struct super_block * configfs_sb = NULL;
+kmem_cache_t *configfs_dir_cachep;
static int configfs_mnt_count = 0;
static struct super_operations configfs_ops = {
@@ -62,6 +63,7 @@ static struct configfs_dirent configfs_root = {
.s_children = LIST_HEAD_INIT(configfs_root.s_children),
.s_element = &configfs_root_group.cg_item,
.s_type = CONFIGFS_ROOT,
+ .s_iattr = NULL,
};
static int configfs_fill_super(struct super_block *sb, void *data, int silent)
@@ -73,9 +75,11 @@ static int configfs_fill_super(struct super_block *sb, void *data, int silent)
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
sb->s_magic = CONFIGFS_MAGIC;
sb->s_op = &configfs_ops;
+ sb->s_time_gran = 1;
configfs_sb = sb;
- inode = configfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO);
+ inode = configfs_new_inode(S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
+ &configfs_root);
if (inode) {
inode->i_op = &configfs_dir_inode_operations;
inode->i_fop = &configfs_dir_operations;
@@ -128,19 +132,31 @@ static decl_subsys(config, NULL, NULL);
static int __init configfs_init(void)
{
- int err;
+ int err = -ENOMEM;
+
+ configfs_dir_cachep = kmem_cache_create("configfs_dir_cache",
+ sizeof(struct configfs_dirent),
+ 0, 0, NULL, NULL);
+ if (!configfs_dir_cachep)
+ goto out;
kset_set_kset_s(&config_subsys, kernel_subsys);
err = subsystem_register(&config_subsys);
- if (err)
- return err;
+ if (err) {
+ kmem_cache_destroy(configfs_dir_cachep);
+ configfs_dir_cachep = NULL;
+ goto out;
+ }
err = register_filesystem(&configfs_fs_type);
if (err) {
printk(KERN_ERR "configfs: Unable to register filesystem!\n");
subsystem_unregister(&config_subsys);
+ kmem_cache_destroy(configfs_dir_cachep);
+ configfs_dir_cachep = NULL;
}
+out:
return err;
}
@@ -148,11 +164,13 @@ static void __exit configfs_exit(void)
{
unregister_filesystem(&configfs_fs_type);
subsystem_unregister(&config_subsys);
+ kmem_cache_destroy(configfs_dir_cachep);
+ configfs_dir_cachep = NULL;
}
MODULE_AUTHOR("Oracle");
MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.1");
+MODULE_VERSION("0.0.2");
MODULE_DESCRIPTION("Simple RAM filesystem for user driven kernel subsystem configuration.");
module_init(configfs_init);
diff --git a/fs/configfs/symlink.c b/fs/configfs/symlink.c
index 50f5840521a..e5512e295cf 100644
--- a/fs/configfs/symlink.c
+++ b/fs/configfs/symlink.c
@@ -162,8 +162,7 @@ int configfs_unlink(struct inode *dir, struct dentry *dentry)
if (!(sd->s_type & CONFIGFS_ITEM_LINK))
goto out;
- if (dentry->d_parent == configfs_sb->s_root)
- BUG();
+ BUG_ON(dentry->d_parent == configfs_sb->s_root);
sl = sd->s_element;
@@ -277,5 +276,6 @@ struct inode_operations configfs_symlink_inode_operations = {
.follow_link = configfs_follow_link,
.readlink = generic_readlink,
.put_link = configfs_put_link,
+ .setattr = configfs_setattr,
};
diff --git a/fs/dcache.c b/fs/dcache.c
index 86bdb93789c..a173bba3266 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -743,7 +743,9 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
dentry->d_op = NULL;
dentry->d_fsdata = NULL;
dentry->d_mounted = 0;
+#ifdef CONFIG_PROFILING
dentry->d_cookie = NULL;
+#endif
INIT_HLIST_NODE(&dentry->d_hash);
INIT_LIST_HEAD(&dentry->d_lru);
INIT_LIST_HEAD(&dentry->d_subdirs);
diff --git a/fs/direct-io.c b/fs/direct-io.c
index 30dbbd1df51..848044af7e1 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -857,6 +857,7 @@ do_holes:
/* Handle holes */
if (!buffer_mapped(map_bh)) {
char *kaddr;
+ loff_t i_size_aligned;
/* AKPM: eargh, -ENOTBLK is a hack */
if (dio->rw == WRITE) {
@@ -864,8 +865,14 @@ do_holes:
return -ENOTBLK;
}
+ /*
+ * Be sure to account for a partial block as the
+ * last block in the file
+ */
+ i_size_aligned = ALIGN(i_size_read(dio->inode),
+ 1 << blkbits);
if (dio->block_in_file >=
- i_size_read(dio->inode)>>blkbits) {
+ i_size_aligned >> blkbits) {
/* We hit eof */
page_cache_release(page);
goto out;
diff --git a/fs/ext2/acl.c b/fs/ext2/acl.c
index 35acc43b897..da52b4a5db6 100644
--- a/fs/ext2/acl.c
+++ b/fs/ext2/acl.c
@@ -220,7 +220,7 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
struct ext2_inode_info *ei = EXT2_I(inode);
int name_index;
void *value = NULL;
- size_t size;
+ size_t size = 0;
int error;
if (S_ISLNK(inode->i_mode))
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index 74714af4ae6..e52765219e1 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -605,7 +605,7 @@ got:
insert_inode_hash(inode);
if (DQUOT_ALLOC_INODE(inode)) {
- err = -ENOSPC;
+ err = -EDQUOT;
goto fail_drop;
}
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 8d6819846fc..cb6f9bd658d 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -221,6 +221,11 @@ static int ext2_show_options(struct seq_file *seq, struct vfsmount *vfs)
seq_puts(seq, ",grpquota");
#endif
+#if defined(CONFIG_EXT2_FS_XIP)
+ if (sbi->s_mount_opt & EXT2_MOUNT_XIP)
+ seq_puts(seq, ",xip");
+#endif
+
return 0;
}
diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c
index 47a9da2dfb4..0d21d558b87 100644
--- a/fs/ext3/acl.c
+++ b/fs/ext3/acl.c
@@ -226,7 +226,7 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type,
struct ext3_inode_info *ei = EXT3_I(inode);
int name_index;
void *value = NULL;
- size_t size;
+ size_t size = 0;
int error;
if (S_ISLNK(inode->i_mode))
diff --git a/fs/fat/file.c b/fs/fat/file.c
index e99c5a73b39..88aa1ae13f9 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -210,10 +210,30 @@ static int fat_free(struct inode *inode, int skip)
if (MSDOS_I(inode)->i_start == 0)
return 0;
- /*
- * Write a new EOF, and get the remaining cluster chain for freeing.
- */
+ fat_cache_inval_inode(inode);
+
wait = IS_DIRSYNC(inode);
+ i_start = free_start = MSDOS_I(inode)->i_start;
+ i_logstart = MSDOS_I(inode)->i_logstart;
+
+ /* First, we write the new file size. */
+ if (!skip) {
+ MSDOS_I(inode)->i_start = 0;
+ MSDOS_I(inode)->i_logstart = 0;
+ }
+ MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
+ inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
+ if (wait) {
+ err = fat_sync_inode(inode);
+ if (err) {
+ MSDOS_I(inode)->i_start = i_start;
+ MSDOS_I(inode)->i_logstart = i_logstart;
+ return err;
+ }
+ } else
+ mark_inode_dirty(inode);
+
+ /* Write a new EOF, and get the remaining cluster chain for freeing. */
if (skip) {
struct fat_entry fatent;
int ret, fclus, dclus;
@@ -244,35 +264,11 @@ static int fat_free(struct inode *inode, int skip)
return ret;
free_start = ret;
- i_start = i_logstart = 0;
- fat_cache_inval_inode(inode);
- } else {
- fat_cache_inval_inode(inode);
-
- i_start = free_start = MSDOS_I(inode)->i_start;
- i_logstart = MSDOS_I(inode)->i_logstart;
- MSDOS_I(inode)->i_start = 0;
- MSDOS_I(inode)->i_logstart = 0;
}
- MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
- inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC;
- if (wait) {
- err = fat_sync_inode(inode);
- if (err)
- goto error;
- } else
- mark_inode_dirty(inode);
inode->i_blocks = skip << (MSDOS_SB(sb)->cluster_bits - 9);
/* Freeing the remained cluster chain */
return fat_free_clusters(inode, free_start);
-
-error:
- if (i_start) {
- MSDOS_I(inode)->i_start = i_start;
- MSDOS_I(inode)->i_logstart = i_logstart;
- }
- return err;
}
void fat_truncate(struct inode *inode)
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
index 32fb0a3f1da..944652e9dde 100644
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -196,19 +196,9 @@ EXPORT_SYMBOL_GPL(fat_date_unix2dos);
int fat_sync_bhs(struct buffer_head **bhs, int nr_bhs)
{
- int i, e, err = 0;
+ int i, err = 0;
- for (i = 0; i < nr_bhs; i++) {
- lock_buffer(bhs[i]);
- if (test_clear_buffer_dirty(bhs[i])) {
- get_bh(bhs[i]);
- bhs[i]->b_end_io = end_buffer_write_sync;
- e = submit_bh(WRITE, bhs[i]);
- if (!err && e)
- err = e;
- } else
- unlock_buffer(bhs[i]);
- }
+ ll_rw_block(SWRITE, nr_bhs, bhs);
for (i = 0; i < nr_bhs; i++) {
wait_on_buffer(bhs[i]);
if (buffer_eopnotsupp(bhs[i])) {
diff --git a/fs/fcntl.c b/fs/fcntl.c
index 5f96786d1c7..dc4a7007f4e 100644
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -208,8 +208,11 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
struct inode * inode = filp->f_dentry->d_inode;
int error = 0;
- /* O_APPEND cannot be cleared if the file is marked as append-only */
- if (!(arg & O_APPEND) && IS_APPEND(inode))
+ /*
+ * O_APPEND cannot be cleared if the file is marked as append-only
+ * and the file is open for write.
+ */
+ if (((arg ^ filp->f_flags) & O_APPEND) && IS_APPEND(inode))
return -EPERM;
/* O_NOATIME can only be set by the owner or superuser */
diff --git a/fs/file.c b/fs/file.c
index fd066b261c7..cea7cbea11d 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -379,7 +379,6 @@ static void __devinit fdtable_defer_list_init(int cpu)
void __init files_defer_init(void)
{
int i;
- /* Really early - can't use for_each_cpu */
- for (i = 0; i < NR_CPUS; i++)
+ for_each_cpu(i)
fdtable_defer_list_init(i);
}
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c
index 4526da8907c..f556a0d5c0d 100644
--- a/fs/fuse/dev.c
+++ b/fs/fuse/dev.c
@@ -120,9 +120,9 @@ struct fuse_req *fuse_get_request(struct fuse_conn *fc)
return do_get_request(fc);
}
+/* Must be called with fuse_lock held */
static void fuse_putback_request(struct fuse_conn *fc, struct fuse_req *req)
{
- spin_lock(&fuse_lock);
if (req->preallocated) {
atomic_dec(&fc->num_waiting);
list_add(&req->list, &fc->unused_list);
@@ -134,11 +134,19 @@ static void fuse_putback_request(struct fuse_conn *fc, struct fuse_req *req)
fc->outstanding_debt--;
else
up(&fc->outstanding_sem);
- spin_unlock(&fuse_lock);
}
void fuse_put_request(struct fuse_conn *fc, struct fuse_req *req)
{
+ if (atomic_dec_and_test(&req->count)) {
+ spin_lock(&fuse_lock);
+ fuse_putback_request(fc, req);
+ spin_unlock(&fuse_lock);
+ }
+}
+
+static void fuse_put_request_locked(struct fuse_conn *fc, struct fuse_req *req)
+{
if (atomic_dec_and_test(&req->count))
fuse_putback_request(fc, req);
}
@@ -163,26 +171,36 @@ void fuse_release_background(struct fuse_req *req)
* still waiting), the 'end' callback is called if given, else the
* reference to the request is released
*
+ * Releasing extra reference for foreground requests must be done
+ * within the same locked region as setting state to finished. This
+ * is because fuse_reset_request() may be called after request is
+ * finished and it must be the sole possessor. If request is
+ * interrupted and put in the background, it will return with an error
+ * and hence never be reset and reused.
+ *
* Called with fuse_lock, unlocks it
*/
static void request_end(struct fuse_conn *fc, struct fuse_req *req)
{
- void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
- req->end = NULL;
list_del(&req->list);
req->state = FUSE_REQ_FINISHED;
- spin_unlock(&fuse_lock);
- if (req->background) {
+ if (!req->background) {
+ wake_up(&req->waitq);
+ fuse_put_request_locked(fc, req);
+ spin_unlock(&fuse_lock);
+ } else {
+ void (*end) (struct fuse_conn *, struct fuse_req *) = req->end;
+ req->end = NULL;
+ spin_unlock(&fuse_lock);
down_read(&fc->sbput_sem);
if (fc->mounted)
fuse_release_background(req);
up_read(&fc->sbput_sem);
+ if (end)
+ end(fc, req);
+ else
+ fuse_put_request(fc, req);
}
- wake_up(&req->waitq);
- if (end)
- end(fc, req);
- else
- fuse_put_request(fc, req);
}
/*
diff --git a/fs/jbd/transaction.c b/fs/jbd/transaction.c
index 429f4b263cf..ca917973c2c 100644
--- a/fs/jbd/transaction.c
+++ b/fs/jbd/transaction.c
@@ -1308,6 +1308,7 @@ int journal_stop(handle_t *handle)
transaction_t *transaction = handle->h_transaction;
journal_t *journal = transaction->t_journal;
int old_handle_count, err;
+ pid_t pid;
J_ASSERT(transaction->t_updates > 0);
J_ASSERT(journal_current_handle() == handle);
@@ -1333,8 +1334,15 @@ int journal_stop(handle_t *handle)
* It doesn't cost much - we're about to run a commit and sleep
* on IO anyway. Speeds up many-threaded, many-dir operations
* by 30x or more...
+ *
+ * But don't do this if this process was the most recent one to
+ * perform a synchronous write. We do this to detect the case where a
+ * single process is doing a stream of sync writes. No point in waiting
+ * for joiners in that case.
*/
- if (handle->h_sync) {
+ pid = current->pid;
+ if (handle->h_sync && journal->j_last_sync_writer != pid) {
+ journal->j_last_sync_writer = pid;
do {
old_handle_count = transaction->t_handle_count;
schedule_timeout_uninterruptible(1);
diff --git a/fs/jffs/intrep.c b/fs/jffs/intrep.c
index b2e95421d93..ce7b54b0b2b 100644
--- a/fs/jffs/intrep.c
+++ b/fs/jffs/intrep.c
@@ -1965,7 +1965,7 @@ retry:
iovec_cnt++;
if (JFFS_GET_PAD_BYTES(raw_inode->nsize)) {
- static char allff[3]={255,255,255};
+ static unsigned char allff[3]={255,255,255};
/* Add some extra padding if necessary */
node_iovec[iovec_cnt].iov_base = allff;
node_iovec[iovec_cnt].iov_len =
diff --git a/fs/libfs.c b/fs/libfs.c
index 63c020e6589..71fd08fa410 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -388,6 +388,7 @@ int simple_fill_super(struct super_block *s, int magic, struct tree_descr *files
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_op = &simple_dir_inode_operations;
inode->i_fop = &simple_dir_operations;
+ inode->i_nlink = 2;
root = d_alloc_root(inode);
if (!root) {
iput(inode);
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index 14552403957..220058d8616 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -22,12 +22,14 @@
#define NLMDBG_FACILITY NLMDBG_CLIENT
#define NLMCLNT_GRACE_WAIT (5*HZ)
#define NLMCLNT_POLL_TIMEOUT (30*HZ)
+#define NLMCLNT_MAX_RETRIES 3
static int nlmclnt_test(struct nlm_rqst *, struct file_lock *);
static int nlmclnt_lock(struct nlm_rqst *, struct file_lock *);
static int nlmclnt_unlock(struct nlm_rqst *, struct file_lock *);
static int nlm_stat_to_errno(u32 stat);
static void nlmclnt_locks_init_private(struct file_lock *fl, struct nlm_host *host);
+static int nlmclnt_cancel(struct nlm_host *, int , struct file_lock *);
static const struct rpc_call_ops nlmclnt_unlock_ops;
static const struct rpc_call_ops nlmclnt_cancel_ops;
@@ -598,7 +600,7 @@ out_unblock:
nlmclnt_finish_block(req);
/* Cancel the blocked request if it is still pending */
if (resp->status == NLM_LCK_BLOCKED)
- nlmclnt_cancel(host, fl);
+ nlmclnt_cancel(host, req->a_args.block, fl);
out:
nlmclnt_release_lockargs(req);
return status;
@@ -728,8 +730,7 @@ static const struct rpc_call_ops nlmclnt_unlock_ops = {
* We always use an async RPC call for this in order not to hang a
* process that has been Ctrl-C'ed.
*/
-int
-nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl)
+static int nlmclnt_cancel(struct nlm_host *host, int block, struct file_lock *fl)
{
struct nlm_rqst *req;
unsigned long flags;
@@ -750,6 +751,7 @@ nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl)
req->a_flags = RPC_TASK_ASYNC;
nlmclnt_setlockargs(req, fl);
+ req->a_args.block = block;
status = nlmclnt_async_call(req, NLMPROC_CANCEL, &nlmclnt_cancel_ops);
if (status < 0) {
@@ -801,6 +803,9 @@ die:
return;
retry_cancel:
+ /* Don't ever retry more than 3 times */
+ if (req->a_retries++ >= NLMCLNT_MAX_RETRIES)
+ goto die;
nlm_rebind_host(req->a_host);
rpc_restart_call(task);
rpc_delay(task, 30 * HZ);
diff --git a/fs/namei.c b/fs/namei.c
index 7ac9fb4acb2..faf61c35308 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -790,7 +790,7 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd)
inode = nd->dentry->d_inode;
if (nd->depth)
- lookup_flags = LOOKUP_FOLLOW;
+ lookup_flags = LOOKUP_FOLLOW | (nd->flags & LOOKUP_CONTINUE);
/* At this point we know we have a real path component. */
for(;;) {
@@ -885,7 +885,8 @@ static fastcall int __link_path_walk(const char * name, struct nameidata *nd)
last_with_slashes:
lookup_flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
last_component:
- nd->flags &= ~LOOKUP_CONTINUE;
+ /* Clear LOOKUP_CONTINUE iff it was previously unset */
+ nd->flags &= lookup_flags | ~LOOKUP_CONTINUE;
if (lookup_flags & LOOKUP_PARENT)
goto lookup_parent;
if (this.name[0] == '.') switch (this.len) {
@@ -1069,6 +1070,8 @@ static int fastcall do_path_lookup(int dfd, const char *name,
unsigned int flags, struct nameidata *nd)
{
int retval = 0;
+ int fput_needed;
+ struct file *file;
nd->last_type = LAST_ROOT; /* if there are only slashes... */
nd->flags = flags;
@@ -1090,29 +1093,22 @@ static int fastcall do_path_lookup(int dfd, const char *name,
nd->mnt = mntget(current->fs->pwdmnt);
nd->dentry = dget(current->fs->pwd);
} else {
- struct file *file;
- int fput_needed;
struct dentry *dentry;
file = fget_light(dfd, &fput_needed);
- if (!file) {
- retval = -EBADF;
- goto out_fail;
- }
+ retval = -EBADF;
+ if (!file)
+ goto unlock_fail;
dentry = file->f_dentry;
- if (!S_ISDIR(dentry->d_inode->i_mode)) {
- retval = -ENOTDIR;
- fput_light(file, fput_needed);
- goto out_fail;
- }
+ retval = -ENOTDIR;
+ if (!S_ISDIR(dentry->d_inode->i_mode))
+ goto fput_unlock_fail;
retval = file_permission(file, MAY_EXEC);
- if (retval) {
- fput_light(file, fput_needed);
- goto out_fail;
- }
+ if (retval)
+ goto fput_unlock_fail;
nd->mnt = mntget(file->f_vfsmnt);
nd->dentry = dget(dentry);
@@ -1126,7 +1122,12 @@ out:
if (unlikely(current->audit_context
&& nd && nd->dentry && nd->dentry->d_inode))
audit_inode(name, nd->dentry->d_inode, flags);
-out_fail:
+ return retval;
+
+fput_unlock_fail:
+ fput_light(file, fput_needed);
+unlock_fail:
+ read_unlock(&current->fs->lock);
return retval;
}
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c
index 10ae377e68f..04ab2fc360e 100644
--- a/fs/nfs/direct.c
+++ b/fs/nfs/direct.c
@@ -481,7 +481,7 @@ retry:
if (wdata->verf.committed != NFS_FILE_SYNC) {
need_commit = 1;
if (memcmp(&first_verf.verifier, &wdata->verf.verifier,
- sizeof(first_verf.verifier)));
+ sizeof(first_verf.verifier)))
goto sync_retry;
}
diff --git a/fs/ocfs2/buffer_head_io.c b/fs/ocfs2/buffer_head_io.c
index d424041b38e..bae3d7548be 100644
--- a/fs/ocfs2/buffer_head_io.c
+++ b/fs/ocfs2/buffer_head_io.c
@@ -58,7 +58,7 @@ int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh,
goto out;
}
- down(&OCFS2_I(inode)->ip_io_sem);
+ mutex_lock(&OCFS2_I(inode)->ip_io_mutex);
lock_buffer(bh);
set_buffer_uptodate(bh);
@@ -82,7 +82,7 @@ int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh,
brelse(bh);
}
- up(&OCFS2_I(inode)->ip_io_sem);
+ mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
out:
mlog_exit(ret);
return ret;
@@ -125,13 +125,13 @@ int ocfs2_read_blocks(struct ocfs2_super *osb, u64 block, int nr,
flags &= ~OCFS2_BH_CACHED;
if (inode)
- down(&OCFS2_I(inode)->ip_io_sem);
+ mutex_lock(&OCFS2_I(inode)->ip_io_mutex);
for (i = 0 ; i < nr ; i++) {
if (bhs[i] == NULL) {
bhs[i] = sb_getblk(sb, block++);
if (bhs[i] == NULL) {
if (inode)
- up(&OCFS2_I(inode)->ip_io_sem);
+ mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
status = -EIO;
mlog_errno(status);
goto bail;
@@ -220,7 +220,7 @@ int ocfs2_read_blocks(struct ocfs2_super *osb, u64 block, int nr,
ocfs2_set_buffer_uptodate(inode, bh);
}
if (inode)
- up(&OCFS2_I(inode)->ip_io_sem);
+ mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
mlog(ML_BH_IO, "block=(%"MLFu64"), nr=(%d), cached=%s\n", block, nr,
(!(flags & OCFS2_BH_CACHED) || ignore_cache) ? "no" : "yes");
diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c
index 7307ba52891..d08971d29b6 100644
--- a/fs/ocfs2/cluster/heartbeat.c
+++ b/fs/ocfs2/cluster/heartbeat.c
@@ -917,8 +917,9 @@ static int o2hb_thread(void *data)
elapsed_msec = o2hb_elapsed_msecs(&before_hb, &after_hb);
mlog(0, "start = %lu.%lu, end = %lu.%lu, msec = %u\n",
- before_hb.tv_sec, before_hb.tv_usec,
- after_hb.tv_sec, after_hb.tv_usec, elapsed_msec);
+ before_hb.tv_sec, (unsigned long) before_hb.tv_usec,
+ after_hb.tv_sec, (unsigned long) after_hb.tv_usec,
+ elapsed_msec);
if (elapsed_msec < reg->hr_timeout_ms) {
/* the kthread api has blocked signals for us so no
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c
index 35d92c01a97..d22d4cf08db 100644
--- a/fs/ocfs2/cluster/tcp.c
+++ b/fs/ocfs2/cluster/tcp.c
@@ -1285,14 +1285,16 @@ static void o2net_idle_timer(unsigned long data)
mlog(ML_NOTICE, "here are some times that might help debug the "
"situation: (tmr %ld.%ld now %ld.%ld dr %ld.%ld adv "
"%ld.%ld:%ld.%ld func (%08x:%u) %ld.%ld:%ld.%ld)\n",
- sc->sc_tv_timer.tv_sec, sc->sc_tv_timer.tv_usec,
- now.tv_sec, now.tv_usec,
- sc->sc_tv_data_ready.tv_sec, sc->sc_tv_data_ready.tv_usec,
- sc->sc_tv_advance_start.tv_sec, sc->sc_tv_advance_start.tv_usec,
- sc->sc_tv_advance_stop.tv_sec, sc->sc_tv_advance_stop.tv_usec,
+ sc->sc_tv_timer.tv_sec, (long) sc->sc_tv_timer.tv_usec,
+ now.tv_sec, (long) now.tv_usec,
+ sc->sc_tv_data_ready.tv_sec, (long) sc->sc_tv_data_ready.tv_usec,
+ sc->sc_tv_advance_start.tv_sec,
+ (long) sc->sc_tv_advance_start.tv_usec,
+ sc->sc_tv_advance_stop.tv_sec,
+ (long) sc->sc_tv_advance_stop.tv_usec,
sc->sc_msg_key, sc->sc_msg_type,
- sc->sc_tv_func_start.tv_sec, sc->sc_tv_func_start.tv_usec,
- sc->sc_tv_func_stop.tv_sec, sc->sc_tv_func_stop.tv_usec);
+ sc->sc_tv_func_start.tv_sec, (long) sc->sc_tv_func_start.tv_usec,
+ sc->sc_tv_func_stop.tv_sec, (long) sc->sc_tv_func_stop.tv_usec);
o2net_sc_queue_work(sc, &sc->sc_shutdown_work);
}
diff --git a/fs/ocfs2/dlm/dlmcommon.h b/fs/ocfs2/dlm/dlmcommon.h
index 3fecba0a602..42eb53b5293 100644
--- a/fs/ocfs2/dlm/dlmcommon.h
+++ b/fs/ocfs2/dlm/dlmcommon.h
@@ -657,6 +657,7 @@ void dlm_complete_thread(struct dlm_ctxt *dlm);
int dlm_launch_recovery_thread(struct dlm_ctxt *dlm);
void dlm_complete_recovery_thread(struct dlm_ctxt *dlm);
void dlm_wait_for_recovery(struct dlm_ctxt *dlm);
+int dlm_is_node_dead(struct dlm_ctxt *dlm, u8 node);
void dlm_put(struct dlm_ctxt *dlm);
struct dlm_ctxt *dlm_grab(struct dlm_ctxt *dlm);
diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c
index da3c22045f8..6ee30837389 100644
--- a/fs/ocfs2/dlm/dlmdomain.c
+++ b/fs/ocfs2/dlm/dlmdomain.c
@@ -573,8 +573,11 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data)
spin_lock(&dlm_domain_lock);
dlm = __dlm_lookup_domain_full(query->domain, query->name_len);
/* Once the dlm ctxt is marked as leaving then we don't want
- * to be put in someone's domain map. */
+ * to be put in someone's domain map.
+ * Also, explicitly disallow joining at certain troublesome
+ * times (ie. during recovery). */
if (dlm && dlm->dlm_state != DLM_CTXT_LEAVING) {
+ int bit = query->node_idx;
spin_lock(&dlm->spinlock);
if (dlm->dlm_state == DLM_CTXT_NEW &&
@@ -586,6 +589,19 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data)
} else if (dlm->joining_node != DLM_LOCK_RES_OWNER_UNKNOWN) {
/* Disallow parallel joins. */
response = JOIN_DISALLOW;
+ } else if (dlm->reco.state & DLM_RECO_STATE_ACTIVE) {
+ mlog(ML_NOTICE, "node %u trying to join, but recovery "
+ "is ongoing.\n", bit);
+ response = JOIN_DISALLOW;
+ } else if (test_bit(bit, dlm->recovery_map)) {
+ mlog(ML_NOTICE, "node %u trying to join, but it "
+ "still needs recovery.\n", bit);
+ response = JOIN_DISALLOW;
+ } else if (test_bit(bit, dlm->domain_map)) {
+ mlog(ML_NOTICE, "node %u trying to join, but it "
+ "is still in the domain! needs recovery?\n",
+ bit);
+ response = JOIN_DISALLOW;
} else {
/* Alright we're fully a part of this domain
* so we keep some state as to who's joining
diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c
index 27e984f7e4c..a3194fe173d 100644
--- a/fs/ocfs2/dlm/dlmmaster.c
+++ b/fs/ocfs2/dlm/dlmmaster.c
@@ -1050,17 +1050,10 @@ static int dlm_restart_lock_mastery(struct dlm_ctxt *dlm,
node = dlm_bitmap_diff_iter_next(&bdi, &sc);
while (node >= 0) {
if (sc == NODE_UP) {
- /* a node came up. easy. might not even need
- * to talk to it if its node number is higher
- * or if we are already blocked. */
- mlog(0, "node up! %d\n", node);
- if (blocked)
- goto next;
-
- if (node > dlm->node_num) {
- mlog(0, "node > this node. skipping.\n");
- goto next;
- }
+ /* a node came up. clear any old vote from
+ * the response map and set it in the vote map
+ * then restart the mastery. */
+ mlog(ML_NOTICE, "node %d up while restarting\n", node);
/* redo the master request, but only for the new node */
mlog(0, "sending request to new node\n");
@@ -2005,6 +1998,15 @@ fail:
break;
mlog(0, "timed out during migration\n");
+ /* avoid hang during shutdown when migrating lockres
+ * to a node which also goes down */
+ if (dlm_is_node_dead(dlm, target)) {
+ mlog(0, "%s:%.*s: expected migration target %u "
+ "is no longer up. restarting.\n",
+ dlm->name, res->lockname.len,
+ res->lockname.name, target);
+ ret = -ERESTARTSYS;
+ }
}
if (ret == -ERESTARTSYS) {
/* migration failed, detach and clean up mle */
diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c
index 0c8eb1093f0..186e9a76aa5 100644
--- a/fs/ocfs2/dlm/dlmrecovery.c
+++ b/fs/ocfs2/dlm/dlmrecovery.c
@@ -39,6 +39,7 @@
#include <linux/inet.h>
#include <linux/timer.h>
#include <linux/kthread.h>
+#include <linux/delay.h>
#include "cluster/heartbeat.h"
@@ -256,6 +257,27 @@ static int dlm_recovery_thread(void *data)
return 0;
}
+/* returns true when the recovery master has contacted us */
+static int dlm_reco_master_ready(struct dlm_ctxt *dlm)
+{
+ int ready;
+ spin_lock(&dlm->spinlock);
+ ready = (dlm->reco.new_master != O2NM_INVALID_NODE_NUM);
+ spin_unlock(&dlm->spinlock);
+ return ready;
+}
+
+/* returns true if node is no longer in the domain
+ * could be dead or just not joined */
+int dlm_is_node_dead(struct dlm_ctxt *dlm, u8 node)
+{
+ int dead;
+ spin_lock(&dlm->spinlock);
+ dead = test_bit(node, dlm->domain_map);
+ spin_unlock(&dlm->spinlock);
+ return dead;
+}
+
/* callers of the top-level api calls (dlmlock/dlmunlock) should
* block on the dlm->reco.event when recovery is in progress.
* the dlm recovery thread will set this state when it begins
@@ -297,6 +319,7 @@ static void dlm_end_recovery(struct dlm_ctxt *dlm)
static int dlm_do_recovery(struct dlm_ctxt *dlm)
{
int status = 0;
+ int ret;
spin_lock(&dlm->spinlock);
@@ -343,10 +366,13 @@ static int dlm_do_recovery(struct dlm_ctxt *dlm)
goto master_here;
if (dlm->reco.new_master == O2NM_INVALID_NODE_NUM) {
- /* choose a new master */
- if (!dlm_pick_recovery_master(dlm)) {
+ /* choose a new master, returns 0 if this node
+ * is the master, -EEXIST if it's another node.
+ * this does not return until a new master is chosen
+ * or recovery completes entirely. */
+ ret = dlm_pick_recovery_master(dlm);
+ if (!ret) {
/* already notified everyone. go. */
- dlm->reco.new_master = dlm->node_num;
goto master_here;
}
mlog(0, "another node will master this recovery session.\n");
@@ -371,8 +397,13 @@ master_here:
if (status < 0) {
mlog(ML_ERROR, "error %d remastering locks for node %u, "
"retrying.\n", status, dlm->reco.dead_node);
+ /* yield a bit to allow any final network messages
+ * to get handled on remaining nodes */
+ msleep(100);
} else {
/* success! see if any other nodes need recovery */
+ mlog(0, "DONE mastering recovery of %s:%u here(this=%u)!\n",
+ dlm->name, dlm->reco.dead_node, dlm->node_num);
dlm_reset_recovery(dlm);
}
dlm_end_recovery(dlm);
@@ -477,7 +508,7 @@ static int dlm_remaster_locks(struct dlm_ctxt *dlm, u8 dead_node)
BUG();
break;
case DLM_RECO_NODE_DATA_DEAD:
- mlog(0, "node %u died after "
+ mlog(ML_NOTICE, "node %u died after "
"requesting recovery info for "
"node %u\n", ndata->node_num,
dead_node);
@@ -485,6 +516,19 @@ static int dlm_remaster_locks(struct dlm_ctxt *dlm, u8 dead_node)
// start all over
destroy = 1;
status = -EAGAIN;
+ /* instead of spinning like crazy here,
+ * wait for the domain map to catch up
+ * with the network state. otherwise this
+ * can be hit hundreds of times before
+ * the node is really seen as dead. */
+ wait_event_timeout(dlm->dlm_reco_thread_wq,
+ dlm_is_node_dead(dlm,
+ ndata->node_num),
+ msecs_to_jiffies(1000));
+ mlog(0, "waited 1 sec for %u, "
+ "dead? %s\n", ndata->node_num,
+ dlm_is_node_dead(dlm, ndata->node_num) ?
+ "yes" : "no");
goto leave;
case DLM_RECO_NODE_DATA_RECEIVING:
case DLM_RECO_NODE_DATA_REQUESTED:
@@ -678,11 +722,27 @@ static void dlm_request_all_locks_worker(struct dlm_work_item *item, void *data)
dlm = item->dlm;
dead_node = item->u.ral.dead_node;
reco_master = item->u.ral.reco_master;
+ mres = (struct dlm_migratable_lockres *)data;
+
+ if (dead_node != dlm->reco.dead_node ||
+ reco_master != dlm->reco.new_master) {
+ /* show extra debug info if the recovery state is messed */
+ mlog(ML_ERROR, "%s: bad reco state: reco(dead=%u, master=%u), "
+ "request(dead=%u, master=%u)\n",
+ dlm->name, dlm->reco.dead_node, dlm->reco.new_master,
+ dead_node, reco_master);
+ mlog(ML_ERROR, "%s: name=%.*s master=%u locks=%u/%u flags=%u "
+ "entry[0]={c=%"MLFu64",l=%u,f=%u,t=%d,ct=%d,hb=%d,n=%u}\n",
+ dlm->name, mres->lockname_len, mres->lockname, mres->master,
+ mres->num_locks, mres->total_locks, mres->flags,
+ mres->ml[0].cookie, mres->ml[0].list, mres->ml[0].flags,
+ mres->ml[0].type, mres->ml[0].convert_type,
+ mres->ml[0].highest_blocked, mres->ml[0].node);
+ BUG();
+ }
BUG_ON(dead_node != dlm->reco.dead_node);
BUG_ON(reco_master != dlm->reco.new_master);
- mres = (struct dlm_migratable_lockres *)data;
-
/* lock resources should have already been moved to the
* dlm->reco.resources list. now move items from that list
* to a temp list if the dead owner matches. note that the
@@ -757,15 +817,18 @@ int dlm_reco_data_done_handler(struct o2net_msg *msg, u32 len, void *data)
continue;
switch (ndata->state) {
+ /* should have moved beyond INIT but not to FINALIZE yet */
case DLM_RECO_NODE_DATA_INIT:
case DLM_RECO_NODE_DATA_DEAD:
- case DLM_RECO_NODE_DATA_DONE:
case DLM_RECO_NODE_DATA_FINALIZE_SENT:
mlog(ML_ERROR, "bad ndata state for node %u:"
" state=%d\n", ndata->node_num,
ndata->state);
BUG();
break;
+ /* these states are possible at this point, anywhere along
+ * the line of recovery */
+ case DLM_RECO_NODE_DATA_DONE:
case DLM_RECO_NODE_DATA_RECEIVING:
case DLM_RECO_NODE_DATA_REQUESTED:
case DLM_RECO_NODE_DATA_REQUESTING:
@@ -799,13 +862,31 @@ static void dlm_move_reco_locks_to_list(struct dlm_ctxt *dlm,
{
struct dlm_lock_resource *res;
struct list_head *iter, *iter2;
+ struct dlm_lock *lock;
spin_lock(&dlm->spinlock);
list_for_each_safe(iter, iter2, &dlm->reco.resources) {
res = list_entry (iter, struct dlm_lock_resource, recovering);
+ /* always prune any $RECOVERY entries for dead nodes,
+ * otherwise hangs can occur during later recovery */
if (dlm_is_recovery_lock(res->lockname.name,
- res->lockname.len))
+ res->lockname.len)) {
+ spin_lock(&res->spinlock);
+ list_for_each_entry(lock, &res->granted, list) {
+ if (lock->ml.node == dead_node) {
+ mlog(0, "AHA! there was "
+ "a $RECOVERY lock for dead "
+ "node %u (%s)!\n",
+ dead_node, dlm->name);
+ list_del_init(&lock->list);
+ dlm_lock_put(lock);
+ break;
+ }
+ }
+ spin_unlock(&res->spinlock);
continue;
+ }
+
if (res->owner == dead_node) {
mlog(0, "found lockres owned by dead node while "
"doing recovery for node %u. sending it.\n",
@@ -1179,7 +1260,7 @@ static void dlm_mig_lockres_worker(struct dlm_work_item *item, void *data)
again:
ret = dlm_lockres_master_requery(dlm, res, &real_master);
if (ret < 0) {
- mlog(0, "dlm_lockres_master_requery failure: %d\n",
+ mlog(0, "dlm_lockres_master_requery ret=%d\n",
ret);
goto again;
}
@@ -1757,6 +1838,7 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node)
struct dlm_lock_resource *res;
int i;
struct list_head *bucket;
+ struct dlm_lock *lock;
/* purge any stale mles */
@@ -1780,10 +1862,25 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node)
bucket = &(dlm->resources[i]);
list_for_each(iter, bucket) {
res = list_entry (iter, struct dlm_lock_resource, list);
+ /* always prune any $RECOVERY entries for dead nodes,
+ * otherwise hangs can occur during later recovery */
if (dlm_is_recovery_lock(res->lockname.name,
- res->lockname.len))
+ res->lockname.len)) {
+ spin_lock(&res->spinlock);
+ list_for_each_entry(lock, &res->granted, list) {
+ if (lock->ml.node == dead_node) {
+ mlog(0, "AHA! there was "
+ "a $RECOVERY lock for dead "
+ "node %u (%s)!\n",
+ dead_node, dlm->name);
+ list_del_init(&lock->list);
+ dlm_lock_put(lock);
+ break;
+ }
+ }
+ spin_unlock(&res->spinlock);
continue;
-
+ }
spin_lock(&res->spinlock);
/* zero the lvb if necessary */
dlm_revalidate_lvb(dlm, res, dead_node);
@@ -1869,12 +1966,9 @@ void dlm_hb_node_up_cb(struct o2nm_node *node, int idx, void *data)
return;
spin_lock(&dlm->spinlock);
-
set_bit(idx, dlm->live_nodes_map);
-
- /* notify any mles attached to the heartbeat events */
- dlm_hb_event_notify_attached(dlm, idx, 1);
-
+ /* do NOT notify mle attached to the heartbeat events.
+ * new nodes are not interesting in mastery until joined. */
spin_unlock(&dlm->spinlock);
dlm_put(dlm);
@@ -1897,7 +1991,18 @@ static void dlm_reco_unlock_ast(void *astdata, enum dlm_status st)
mlog(0, "unlockast for recovery lock fired!\n");
}
-
+/*
+ * dlm_pick_recovery_master will continually attempt to use
+ * dlmlock() on the special "$RECOVERY" lockres with the
+ * LKM_NOQUEUE flag to get an EX. every thread that enters
+ * this function on each node racing to become the recovery
+ * master will not stop attempting this until either:
+ * a) this node gets the EX (and becomes the recovery master),
+ * or b) dlm->reco.new_master gets set to some nodenum
+ * != O2NM_INVALID_NODE_NUM (another node will do the reco).
+ * so each time a recovery master is needed, the entire cluster
+ * will sync at this point. if the new master dies, that will
+ * be detected in dlm_do_recovery */
static int dlm_pick_recovery_master(struct dlm_ctxt *dlm)
{
enum dlm_status ret;
@@ -1906,23 +2011,45 @@ static int dlm_pick_recovery_master(struct dlm_ctxt *dlm)
mlog(0, "starting recovery of %s at %lu, dead=%u, this=%u\n",
dlm->name, jiffies, dlm->reco.dead_node, dlm->node_num);
-retry:
+again:
memset(&lksb, 0, sizeof(lksb));
ret = dlmlock(dlm, LKM_EXMODE, &lksb, LKM_NOQUEUE|LKM_RECOVERY,
DLM_RECOVERY_LOCK_NAME, dlm_reco_ast, dlm, dlm_reco_bast);
+ mlog(0, "%s: dlmlock($RECOVERY) returned %d, lksb=%d\n",
+ dlm->name, ret, lksb.status);
+
if (ret == DLM_NORMAL) {
mlog(0, "dlm=%s dlmlock says I got it (this=%u)\n",
dlm->name, dlm->node_num);
- /* I am master, send message to all nodes saying
- * that I am beginning a recovery session */
- status = dlm_send_begin_reco_message(dlm,
- dlm->reco.dead_node);
+
+ /* got the EX lock. check to see if another node
+ * just became the reco master */
+ if (dlm_reco_master_ready(dlm)) {
+ mlog(0, "%s: got reco EX lock, but %u will "
+ "do the recovery\n", dlm->name,
+ dlm->reco.new_master);
+ status = -EEXIST;
+ } else {
+ status = dlm_send_begin_reco_message(dlm,
+ dlm->reco.dead_node);
+ /* this always succeeds */
+ BUG_ON(status);
+
+ /* set the new_master to this node */
+ spin_lock(&dlm->spinlock);
+ dlm->reco.new_master = dlm->node_num;
+ spin_unlock(&dlm->spinlock);
+ }
/* recovery lock is a special case. ast will not get fired,
* so just go ahead and unlock it. */
ret = dlmunlock(dlm, &lksb, 0, dlm_reco_unlock_ast, dlm);
+ if (ret == DLM_DENIED) {
+ mlog(0, "got DLM_DENIED, trying LKM_CANCEL\n");
+ ret = dlmunlock(dlm, &lksb, LKM_CANCEL, dlm_reco_unlock_ast, dlm);
+ }
if (ret != DLM_NORMAL) {
/* this would really suck. this could only happen
* if there was a network error during the unlock
@@ -1930,20 +2057,42 @@ retry:
* is actually "done" and the lock structure is
* even freed. we can continue, but only
* because this specific lock name is special. */
- mlog(0, "dlmunlock returned %d\n", ret);
- }
-
- if (status < 0) {
- mlog(0, "failed to send recovery message. "
- "must retry with new node map.\n");
- goto retry;
+ mlog(ML_ERROR, "dlmunlock returned %d\n", ret);
}
} else if (ret == DLM_NOTQUEUED) {
mlog(0, "dlm=%s dlmlock says another node got it (this=%u)\n",
dlm->name, dlm->node_num);
/* another node is master. wait on
- * reco.new_master != O2NM_INVALID_NODE_NUM */
+ * reco.new_master != O2NM_INVALID_NODE_NUM
+ * for at most one second */
+ wait_event_timeout(dlm->dlm_reco_thread_wq,
+ dlm_reco_master_ready(dlm),
+ msecs_to_jiffies(1000));
+ if (!dlm_reco_master_ready(dlm)) {
+ mlog(0, "%s: reco master taking awhile\n",
+ dlm->name);
+ goto again;
+ }
+ /* another node has informed this one that it is reco master */
+ mlog(0, "%s: reco master %u is ready to recover %u\n",
+ dlm->name, dlm->reco.new_master, dlm->reco.dead_node);
status = -EEXIST;
+ } else {
+ struct dlm_lock_resource *res;
+
+ /* dlmlock returned something other than NOTQUEUED or NORMAL */
+ mlog(ML_ERROR, "%s: got %s from dlmlock($RECOVERY), "
+ "lksb.status=%s\n", dlm->name, dlm_errname(ret),
+ dlm_errname(lksb.status));
+ res = dlm_lookup_lockres(dlm, DLM_RECOVERY_LOCK_NAME,
+ DLM_RECOVERY_LOCK_NAME_LEN);
+ if (res) {
+ dlm_print_one_lock_resource(res);
+ dlm_lockres_put(res);
+ } else {
+ mlog(ML_ERROR, "recovery lock not found\n");
+ }
+ BUG();
}
return status;
@@ -1982,7 +2131,7 @@ static int dlm_send_begin_reco_message(struct dlm_ctxt *dlm, u8 dead_node)
mlog(0, "not sending begin reco to self\n");
continue;
}
-
+retry:
ret = -EINVAL;
mlog(0, "attempting to send begin reco msg to %d\n",
nodenum);
@@ -1991,8 +2140,17 @@ static int dlm_send_begin_reco_message(struct dlm_ctxt *dlm, u8 dead_node)
/* negative status is handled ok by caller here */
if (ret >= 0)
ret = status;
+ if (dlm_is_host_down(ret)) {
+ /* node is down. not involved in recovery
+ * so just keep going */
+ mlog(0, "%s: node %u was down when sending "
+ "begin reco msg (%d)\n", dlm->name, nodenum, ret);
+ ret = 0;
+ }
if (ret < 0) {
struct dlm_lock_resource *res;
+ /* this is now a serious problem, possibly ENOMEM
+ * in the network stack. must retry */
mlog_errno(ret);
mlog(ML_ERROR, "begin reco of dlm %s to node %u "
" returned %d\n", dlm->name, nodenum, ret);
@@ -2004,7 +2162,10 @@ static int dlm_send_begin_reco_message(struct dlm_ctxt *dlm, u8 dead_node)
} else {
mlog(ML_ERROR, "recovery lock not found\n");
}
- break;
+ /* sleep for a bit in hopes that we can avoid
+ * another ENOMEM */
+ msleep(100);
+ goto retry;
}
}
@@ -2027,19 +2188,34 @@ int dlm_begin_reco_handler(struct o2net_msg *msg, u32 len, void *data)
spin_lock(&dlm->spinlock);
if (dlm->reco.new_master != O2NM_INVALID_NODE_NUM) {
- mlog(0, "new_master already set to %u!\n",
- dlm->reco.new_master);
+ if (test_bit(dlm->reco.new_master, dlm->recovery_map)) {
+ mlog(0, "%s: new_master %u died, changing "
+ "to %u\n", dlm->name, dlm->reco.new_master,
+ br->node_idx);
+ } else {
+ mlog(0, "%s: new_master %u NOT DEAD, changing "
+ "to %u\n", dlm->name, dlm->reco.new_master,
+ br->node_idx);
+ /* may not have seen the new master as dead yet */
+ }
}
if (dlm->reco.dead_node != O2NM_INVALID_NODE_NUM) {
- mlog(0, "dead_node already set to %u!\n",
- dlm->reco.dead_node);
+ mlog(ML_NOTICE, "%s: dead_node previously set to %u, "
+ "node %u changing it to %u\n", dlm->name,
+ dlm->reco.dead_node, br->node_idx, br->dead_node);
}
dlm->reco.new_master = br->node_idx;
dlm->reco.dead_node = br->dead_node;
if (!test_bit(br->dead_node, dlm->recovery_map)) {
- mlog(ML_ERROR, "recovery master %u sees %u as dead, but this "
+ mlog(0, "recovery master %u sees %u as dead, but this "
"node has not yet. marking %u as dead\n",
br->node_idx, br->dead_node, br->dead_node);
+ if (!test_bit(br->dead_node, dlm->domain_map) ||
+ !test_bit(br->dead_node, dlm->live_nodes_map))
+ mlog(0, "%u not in domain/live_nodes map "
+ "so setting it in reco map manually\n",
+ br->dead_node);
+ set_bit(br->dead_node, dlm->recovery_map);
__dlm_hb_node_down(dlm, br->dead_node);
}
spin_unlock(&dlm->spinlock);
diff --git a/fs/ocfs2/dlm/dlmunlock.c b/fs/ocfs2/dlm/dlmunlock.c
index cec2ce1cd31..c95f08d2e92 100644
--- a/fs/ocfs2/dlm/dlmunlock.c
+++ b/fs/ocfs2/dlm/dlmunlock.c
@@ -188,6 +188,19 @@ static enum dlm_status dlmunlock_common(struct dlm_ctxt *dlm,
actions &= ~(DLM_UNLOCK_REMOVE_LOCK|
DLM_UNLOCK_REGRANT_LOCK|
DLM_UNLOCK_CLEAR_CONVERT_TYPE);
+ } else if (status == DLM_RECOVERING ||
+ status == DLM_MIGRATING ||
+ status == DLM_FORWARD) {
+ /* must clear the actions because this unlock
+ * is about to be retried. cannot free or do
+ * any list manipulation. */
+ mlog(0, "%s:%.*s: clearing actions, %s\n",
+ dlm->name, res->lockname.len,
+ res->lockname.name,
+ status==DLM_RECOVERING?"recovering":
+ (status==DLM_MIGRATING?"migrating":
+ "forward"));
+ actions = 0;
}
if (flags & LKM_CANCEL)
lock->cancel_pending = 0;
diff --git a/fs/ocfs2/dlm/userdlm.c b/fs/ocfs2/dlm/userdlm.c
index e1fdd288796..c3764f4744e 100644
--- a/fs/ocfs2/dlm/userdlm.c
+++ b/fs/ocfs2/dlm/userdlm.c
@@ -27,7 +27,7 @@
* Boston, MA 021110-1307, USA.
*/
-#include <asm/signal.h>
+#include <linux/signal.h>
#include <linux/module.h>
#include <linux/fs.h>
diff --git a/fs/ocfs2/extent_map.c b/fs/ocfs2/extent_map.c
index f2fb40cd296..b6ba292e954 100644
--- a/fs/ocfs2/extent_map.c
+++ b/fs/ocfs2/extent_map.c
@@ -262,8 +262,7 @@ static int ocfs2_extent_map_find_leaf(struct inode *inode,
el = &eb->h_list;
}
- if (el->l_tree_depth)
- BUG();
+ BUG_ON(el->l_tree_depth);
for (i = 0; i < le16_to_cpu(el->l_next_free_rec); i++) {
rec = &el->l_recs[i];
@@ -364,8 +363,8 @@ static int ocfs2_extent_map_lookup_read(struct inode *inode,
return ret;
}
- if (ent->e_tree_depth)
- BUG(); /* FIXME: Make sure this isn't a corruption */
+ /* FIXME: Make sure this isn't a corruption */
+ BUG_ON(ent->e_tree_depth);
*ret_ent = ent;
@@ -423,8 +422,7 @@ static int ocfs2_extent_map_try_insert(struct inode *inode,
le32_to_cpu(rec->e_clusters), NULL,
NULL);
- if (!old_ent)
- BUG();
+ BUG_ON(!old_ent);
ret = -EEXIST;
if (old_ent->e_tree_depth < tree_depth)
@@ -988,7 +986,7 @@ int __init init_ocfs2_extent_maps(void)
return 0;
}
-void __exit exit_ocfs2_extent_maps(void)
+void exit_ocfs2_extent_maps(void)
{
kmem_cache_destroy(ocfs2_em_ent_cachep);
}
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index eaf33caa0a1..1715bc90e70 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -1022,8 +1022,9 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
}
newsize = count + saved_pos;
- mlog(0, "pos=%lld newsize=%"MLFu64" cursize=%lld\n",
- saved_pos, newsize, i_size_read(inode));
+ mlog(0, "pos=%lld newsize=%lld cursize=%lld\n",
+ (long long) saved_pos, (long long) newsize,
+ (long long) i_size_read(inode));
/* No need for a higher level metadata lock if we're
* never going past i_size. */
@@ -1042,8 +1043,9 @@ static ssize_t ocfs2_file_aio_write(struct kiocb *iocb,
spin_unlock(&OCFS2_I(inode)->ip_lock);
mlog(0, "Writing at EOF, may need more allocation: "
- "i_size = %lld, newsize = %"MLFu64", need %u clusters\n",
- i_size_read(inode), newsize, clusters);
+ "i_size = %lld, newsize = %lld, need %u clusters\n",
+ (long long) i_size_read(inode), (long long) newsize,
+ clusters);
/* We only want to continue the rest of this loop if
* our extend will actually require more
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index d4ecc062771..8122489c576 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -903,10 +903,10 @@ void ocfs2_clear_inode(struct inode *inode)
"Clear inode of %"MLFu64", inode is locked\n",
oi->ip_blkno);
- mlog_bug_on_msg(down_trylock(&oi->ip_io_sem),
- "Clear inode of %"MLFu64", io_sem is locked\n",
+ mlog_bug_on_msg(!mutex_trylock(&oi->ip_io_mutex),
+ "Clear inode of %"MLFu64", io_mutex is locked\n",
oi->ip_blkno);
- up(&oi->ip_io_sem);
+ mutex_unlock(&oi->ip_io_mutex);
/*
* down_trylock() returns 0, down_write_trylock() returns 1
diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h
index 9b017743365..84c50796128 100644
--- a/fs/ocfs2/inode.h
+++ b/fs/ocfs2/inode.h
@@ -46,10 +46,10 @@ struct ocfs2_inode_info
struct list_head ip_io_markers;
int ip_orphaned_slot;
- struct semaphore ip_io_sem;
+ struct mutex ip_io_mutex;
/* Used by the journalling code to attach an inode to a
- * handle. These are protected by ip_io_sem in order to lock
+ * handle. These are protected by ip_io_mutex in order to lock
* out other I/O to the inode until we either commit or
* abort. */
struct list_head ip_handle_list;
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
index 303c8d96457..fa0bcac5cea 100644
--- a/fs/ocfs2/journal.c
+++ b/fs/ocfs2/journal.c
@@ -147,8 +147,7 @@ struct ocfs2_journal_handle *ocfs2_start_trans(struct ocfs2_super *osb,
mlog_entry("(max_buffs = %d)\n", max_buffs);
- if (!osb || !osb->journal->j_journal)
- BUG();
+ BUG_ON(!osb || !osb->journal->j_journal);
if (ocfs2_is_hard_readonly(osb)) {
ret = -EROFS;
@@ -401,7 +400,7 @@ int ocfs2_journal_access(struct ocfs2_journal_handle *handle,
* j_trans_barrier for us. */
ocfs2_set_inode_lock_trans(OCFS2_SB(inode->i_sb)->journal, inode);
- down(&OCFS2_I(inode)->ip_io_sem);
+ mutex_lock(&OCFS2_I(inode)->ip_io_mutex);
switch (type) {
case OCFS2_JOURNAL_ACCESS_CREATE:
case OCFS2_JOURNAL_ACCESS_WRITE:
@@ -416,7 +415,7 @@ int ocfs2_journal_access(struct ocfs2_journal_handle *handle,
status = -EINVAL;
mlog(ML_ERROR, "Uknown access type!\n");
}
- up(&OCFS2_I(inode)->ip_io_sem);
+ mutex_unlock(&OCFS2_I(inode)->ip_io_mutex);
if (status < 0)
mlog(ML_ERROR, "Error %d getting %d access to buffer!\n",
@@ -561,7 +560,11 @@ int ocfs2_journal_init(struct ocfs2_journal *journal, int *dirty)
SET_INODE_JOURNAL(inode);
OCFS2_I(inode)->ip_open_count++;
- status = ocfs2_meta_lock(inode, NULL, &bh, 1);
+ /* Skip recovery waits here - journal inode metadata never
+ * changes in a live cluster so it can be considered an
+ * exception to the rule. */
+ status = ocfs2_meta_lock_full(inode, NULL, &bh, 1,
+ OCFS2_META_LOCK_RECOVERY);
if (status < 0) {
if (status != -ERESTARTSYS)
mlog(ML_ERROR, "Could not get lock on journal!\n");
@@ -672,8 +675,7 @@ void ocfs2_journal_shutdown(struct ocfs2_super *osb)
mlog_entry_void();
- if (!osb)
- BUG();
+ BUG_ON(!osb);
journal = osb->journal;
if (!journal)
@@ -805,8 +807,7 @@ int ocfs2_journal_wipe(struct ocfs2_journal *journal, int full)
mlog_entry_void();
- if (!journal)
- BUG();
+ BUG_ON(!journal);
status = journal_wipe(journal->j_journal, full);
if (status < 0) {
@@ -1072,10 +1073,10 @@ restart:
NULL);
bail:
- down(&osb->recovery_lock);
+ mutex_lock(&osb->recovery_lock);
if (!status &&
!ocfs2_node_map_is_empty(osb, &osb->recovery_map)) {
- up(&osb->recovery_lock);
+ mutex_unlock(&osb->recovery_lock);
goto restart;
}
@@ -1083,7 +1084,7 @@ bail:
mb(); /* sync with ocfs2_recovery_thread_running */
wake_up(&osb->recovery_event);
- up(&osb->recovery_lock);
+ mutex_unlock(&osb->recovery_lock);
mlog_exit(status);
/* no one is callint kthread_stop() for us so the kthread() api
@@ -1098,7 +1099,7 @@ void ocfs2_recovery_thread(struct ocfs2_super *osb, int node_num)
mlog_entry("(node_num=%d, osb->node_num = %d)\n",
node_num, osb->node_num);
- down(&osb->recovery_lock);
+ mutex_lock(&osb->recovery_lock);
if (osb->disable_recovery)
goto out;
@@ -1120,7 +1121,7 @@ void ocfs2_recovery_thread(struct ocfs2_super *osb, int node_num)
}
out:
- up(&osb->recovery_lock);
+ mutex_unlock(&osb->recovery_lock);
wake_up(&osb->recovery_event);
mlog_exit_void();
@@ -1271,8 +1272,7 @@ static int ocfs2_recover_node(struct ocfs2_super *osb,
/* Should not ever be called to recover ourselves -- in that
* case we should've called ocfs2_journal_load instead. */
- if (osb->node_num == node_num)
- BUG();
+ BUG_ON(osb->node_num == node_num);
slot_num = ocfs2_node_num_to_slot(si, node_num);
if (slot_num == OCFS2_INVALID_SLOT) {
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h
index f468c600cf9..8d8e4779df9 100644
--- a/fs/ocfs2/ocfs2.h
+++ b/fs/ocfs2/ocfs2.h
@@ -33,6 +33,7 @@
#include <linux/rbtree.h>
#include <linux/workqueue.h>
#include <linux/kref.h>
+#include <linux/mutex.h>
#include "cluster/nodemanager.h"
#include "cluster/heartbeat.h"
@@ -233,7 +234,7 @@ struct ocfs2_super
struct proc_dir_entry *proc_sub_dir; /* points to /proc/fs/ocfs2/<maj_min> */
atomic_t vol_state;
- struct semaphore recovery_lock;
+ struct mutex recovery_lock;
struct task_struct *recovery_thread_task;
int disable_recovery;
wait_queue_head_t checkpoint_event;
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 364d64bd5f1..046824b6b62 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -932,7 +932,7 @@ static void ocfs2_inode_init_once(void *data,
oi->ip_dir_start_lookup = 0;
init_rwsem(&oi->ip_alloc_sem);
- init_MUTEX(&(oi->ip_io_sem));
+ mutex_init(&oi->ip_io_mutex);
oi->ip_blkno = 0ULL;
oi->ip_clusters = 0;
@@ -1137,9 +1137,9 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
/* disable any new recovery threads and wait for any currently
* running ones to exit. Do this before setting the vol_state. */
- down(&osb->recovery_lock);
+ mutex_lock(&osb->recovery_lock);
osb->disable_recovery = 1;
- up(&osb->recovery_lock);
+ mutex_unlock(&osb->recovery_lock);
wait_event(osb->recovery_event, !ocfs2_recovery_thread_running(osb));
/* At this point, we know that no more recovery threads can be
@@ -1254,8 +1254,7 @@ static int ocfs2_initialize_super(struct super_block *sb,
osb->sb = sb;
/* Save off for ocfs2_rw_direct */
osb->s_sectsize_bits = blksize_bits(sector_size);
- if (!osb->s_sectsize_bits)
- BUG();
+ BUG_ON(!osb->s_sectsize_bits);
osb->net_response_ids = 0;
spin_lock_init(&osb->net_response_lock);
@@ -1283,7 +1282,7 @@ static int ocfs2_initialize_super(struct super_block *sb,
snprintf(osb->dev_str, sizeof(osb->dev_str), "%u,%u",
MAJOR(osb->sb->s_dev), MINOR(osb->sb->s_dev));
- init_MUTEX(&osb->recovery_lock);
+ mutex_init(&osb->recovery_lock);
osb->disable_recovery = 0;
osb->recovery_thread_task = NULL;
diff --git a/fs/ocfs2/sysfile.c b/fs/ocfs2/sysfile.c
index 600a8bc5b54..fc29cb7a437 100644
--- a/fs/ocfs2/sysfile.c
+++ b/fs/ocfs2/sysfile.c
@@ -77,8 +77,7 @@ struct inode *ocfs2_get_system_file_inode(struct ocfs2_super *osb,
if (arr && ((inode = *arr) != NULL)) {
/* get a ref in addition to the array ref */
inode = igrab(inode);
- if (!inode)
- BUG();
+ BUG_ON(!inode);
return inode;
}
@@ -89,8 +88,7 @@ struct inode *ocfs2_get_system_file_inode(struct ocfs2_super *osb,
/* add one more if putting into array for first time */
if (arr && inode) {
*arr = igrab(inode);
- if (!*arr)
- BUG();
+ BUG_ON(!*arr);
}
return inode;
}
diff --git a/fs/ocfs2/uptodate.c b/fs/ocfs2/uptodate.c
index 3a0458fd3e1..300b5bedfb2 100644
--- a/fs/ocfs2/uptodate.c
+++ b/fs/ocfs2/uptodate.c
@@ -388,7 +388,7 @@ out_free:
}
}
-/* Item insertion is guarded by ip_io_sem, so the insertion path takes
+/* Item insertion is guarded by ip_io_mutex, so the insertion path takes
* advantage of this by not rechecking for a duplicate insert during
* the slow case. Additionally, if the cache needs to be bumped up to
* a tree, the code will not recheck after acquiring the lock --
@@ -418,7 +418,7 @@ void ocfs2_set_buffer_uptodate(struct inode *inode,
(unsigned long long) bh->b_blocknr);
/* No need to recheck under spinlock - insertion is guarded by
- * ip_io_sem */
+ * ip_io_mutex */
spin_lock(&oi->ip_lock);
if (ocfs2_insert_can_use_array(oi, ci)) {
/* Fast case - it's an array and there's a free
@@ -440,7 +440,7 @@ void ocfs2_set_buffer_uptodate(struct inode *inode,
/* Called against a newly allocated buffer. Most likely nobody should
* be able to read this sort of metadata while it's still being
- * allocated, but this is careful to take ip_io_sem anyway. */
+ * allocated, but this is careful to take ip_io_mutex anyway. */
void ocfs2_set_new_buffer_uptodate(struct inode *inode,
struct buffer_head *bh)
{
@@ -451,9 +451,9 @@ void ocfs2_set_new_buffer_uptodate(struct inode *inode,
set_buffer_uptodate(bh);
- down(&oi->ip_io_sem);
+ mutex_lock(&oi->ip_io_mutex);
ocfs2_set_buffer_uptodate(inode, bh);
- up(&oi->ip_io_sem);
+ mutex_unlock(&oi->ip_io_mutex);
}
/* Requires ip_lock. */
@@ -537,7 +537,7 @@ int __init init_ocfs2_uptodate_cache(void)
return 0;
}
-void __exit exit_ocfs2_uptodate_cache(void)
+void exit_ocfs2_uptodate_cache(void)
{
if (ocfs2_uptodate_cachep)
kmem_cache_destroy(ocfs2_uptodate_cachep);
diff --git a/fs/ocfs2/uptodate.h b/fs/ocfs2/uptodate.h
index e5aacdf4eab..01cd32d26b0 100644
--- a/fs/ocfs2/uptodate.h
+++ b/fs/ocfs2/uptodate.h
@@ -27,7 +27,7 @@
#define OCFS2_UPTODATE_H
int __init init_ocfs2_uptodate_cache(void);
-void __exit exit_ocfs2_uptodate_cache(void);
+void exit_ocfs2_uptodate_cache(void);
void ocfs2_metadata_cache_init(struct inode *inode);
void ocfs2_metadata_cache_purge(struct inode *inode);
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index 8f8014285a3..1d24fead51a 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -548,7 +548,7 @@ static int show_stat(struct seq_file *p, void *v)
}
seq_printf(p, "intr %llu", (unsigned long long)sum);
-#if !defined(CONFIG_PPC64) && !defined(CONFIG_ALPHA)
+#if !defined(CONFIG_PPC64) && !defined(CONFIG_ALPHA) && !defined(CONFIG_IA64)
for (i = 0; i < NR_IRQS; i++)
seq_printf(p, " %u", kstat_irqs(i));
#endif
diff --git a/fs/quota_v2.c b/fs/quota_v2.c
index a4ef91bb4f3..b4199ec3ece 100644
--- a/fs/quota_v2.c
+++ b/fs/quota_v2.c
@@ -35,7 +35,7 @@ static int v2_check_quota_file(struct super_block *sb, int type)
size = sb->s_op->quota_read(sb, type, (char *)&dqhead, sizeof(struct v2_disk_dqheader), 0);
if (size != sizeof(struct v2_disk_dqheader)) {
- printk("quota_v2: failed read expected=%d got=%d\n",
+ printk("quota_v2: failed read expected=%zd got=%zd\n",
sizeof(struct v2_disk_dqheader), size);
return 0;
}
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index 77891de0e02..ef5e5414e7a 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -1125,7 +1125,7 @@ static void handle_attrs(struct super_block *s)
REISERFS_SB(s)->s_mount_opt &= ~(1 << REISERFS_ATTRS);
}
} else if (le32_to_cpu(rs->s_flags) & reiserfs_attrs_cleared) {
- REISERFS_SB(s)->s_mount_opt |= REISERFS_ATTRS;
+ REISERFS_SB(s)->s_mount_opt |= (1 << REISERFS_ATTRS);
}
}
diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c
index 4fae57d9d11..201049ac8a9 100644
--- a/fs/udf/balloc.c
+++ b/fs/udf/balloc.c
@@ -579,10 +579,9 @@ static void udf_table_free_blocks(struct super_block * sb,
{
loffset = nextoffset;
aed->lengthAllocDescs = cpu_to_le32(adsize);
- if (obh)
- sptr = UDF_I_DATA(inode) + nextoffset - udf_file_entry_alloc_offset(inode) + UDF_I_LENEATTR(inode) - adsize;
- else
- sptr = obh->b_data + nextoffset - adsize;
+ sptr = UDF_I_DATA(inode) + nextoffset -
+ udf_file_entry_alloc_offset(inode) +
+ UDF_I_LENEATTR(inode) - adsize;
dptr = nbh->b_data + sizeof(struct allocExtDesc);
memcpy(dptr, sptr, adsize);
nextoffset = sizeof(struct allocExtDesc) + adsize;
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index ca732e79c48..ab9a7629d23 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -296,7 +296,7 @@ static struct dentry *
udf_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
{
struct inode *inode = NULL;
- struct fileIdentDesc cfi, *fi;
+ struct fileIdentDesc cfi;
struct udf_fileident_bh fibh;
if (dentry->d_name.len > UDF_NAME_LEN-2)
@@ -318,7 +318,7 @@ udf_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
else
#endif /* UDF_RECOVERY */
- if ((fi = udf_find_entry(dir, dentry, &fibh, &cfi)))
+ if (udf_find_entry(dir, dentry, &fibh, &cfi))
{
if (fibh.sbh != fibh.ebh)
udf_release_data(fibh.ebh);
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c
index e0c04e36a05..3c3f62ce2ad 100644
--- a/fs/ufs/inode.c
+++ b/fs/ufs/inode.c
@@ -376,7 +376,7 @@ out:
* This function gets the block which contains the fragment.
*/
-static int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create)
+int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create)
{
struct super_block * sb = inode->i_sb;
struct ufs_sb_private_info * uspi = UFS_SB(sb)->s_uspi;
diff --git a/fs/ufs/super.c b/fs/ufs/super.c
index d4aacee593f..e9055ef7f5a 100644
--- a/fs/ufs/super.c
+++ b/fs/ufs/super.c
@@ -388,7 +388,8 @@ static int ufs_parse_options (char * options, unsigned * mount_options)
/*
* Read on-disk structures associated with cylinder groups
*/
-static int ufs_read_cylinder_structures (struct super_block *sb) {
+static int ufs_read_cylinder_structures (struct super_block *sb)
+{
struct ufs_sb_info * sbi = UFS_SB(sb);
struct ufs_sb_private_info * uspi;
struct ufs_super_block *usb;
@@ -415,6 +416,7 @@ static int ufs_read_cylinder_structures (struct super_block *sb) {
base = space = kmalloc(size, GFP_KERNEL);
if (!base)
goto failed;
+ sbi->s_csp = (struct ufs_csum *)space;
for (i = 0; i < blks; i += uspi->s_fpb) {
size = uspi->s_bsize;
if (i + uspi->s_fpb > blks)
@@ -430,7 +432,6 @@ static int ufs_read_cylinder_structures (struct super_block *sb) {
goto failed;
ubh_ubhcpymem (space, ubh, size);
- sbi->s_csp[ufs_fragstoblks(i)]=(struct ufs_csum *)space;
space += size;
ubh_brelse (ubh);
@@ -486,7 +487,8 @@ failed:
* Put on-disk structures associated with cylinder groups and
* write them back to disk
*/
-static void ufs_put_cylinder_structures (struct super_block *sb) {
+static void ufs_put_cylinder_structures (struct super_block *sb)
+{
struct ufs_sb_info * sbi = UFS_SB(sb);
struct ufs_sb_private_info * uspi;
struct ufs_buffer_head * ubh;
@@ -499,7 +501,7 @@ static void ufs_put_cylinder_structures (struct super_block *sb) {
size = uspi->s_cssize;
blks = (size + uspi->s_fsize - 1) >> uspi->s_fshift;
- base = space = (char*) sbi->s_csp[0];
+ base = space = (char*) sbi->s_csp;
for (i = 0; i < blks; i += uspi->s_fpb) {
size = uspi->s_bsize;
if (i + uspi->s_fpb > blks)
diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c
index 61d2e35012a..02e86291ef8 100644
--- a/fs/ufs/truncate.c
+++ b/fs/ufs/truncate.c
@@ -29,6 +29,11 @@
* Idea from Pierre del Perugia <delperug@gla.ecoledoc.ibp.fr>
*/
+/*
+ * Modified to avoid infinite loop on 2006 by
+ * Evgeniy Dushistov <dushistov@mail.ru>
+ */
+
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/ufs_fs.h>
@@ -65,19 +70,16 @@
#define DIRECT_BLOCK ((inode->i_size + uspi->s_bsize - 1) >> uspi->s_bshift)
#define DIRECT_FRAGMENT ((inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift)
-#define DATA_BUFFER_USED(bh) \
- (atomic_read(&bh->b_count)>1 || buffer_locked(bh))
static int ufs_trunc_direct (struct inode * inode)
{
struct ufs_inode_info *ufsi = UFS_I(inode);
struct super_block * sb;
struct ufs_sb_private_info * uspi;
- struct buffer_head * bh;
__fs32 * p;
unsigned frag1, frag2, frag3, frag4, block1, block2;
unsigned frag_to_free, free_count;
- unsigned i, j, tmp;
+ unsigned i, tmp;
int retry;
UFSD(("ENTER\n"))
@@ -117,15 +119,7 @@ static int ufs_trunc_direct (struct inode * inode)
ufs_panic (sb, "ufs_trunc_direct", "internal error");
frag1 = ufs_fragnum (frag1);
frag2 = ufs_fragnum (frag2);
- for (j = frag1; j < frag2; j++) {
- bh = sb_find_get_block (sb, tmp + j);
- if ((bh && DATA_BUFFER_USED(bh)) || tmp != fs32_to_cpu(sb, *p)) {
- retry = 1;
- brelse (bh);
- goto next1;
- }
- bforget (bh);
- }
+
inode->i_blocks -= (frag2-frag1) << uspi->s_nspfshift;
mark_inode_dirty(inode);
ufs_free_fragments (inode, tmp + frag1, frag2 - frag1);
@@ -140,15 +134,7 @@ next1:
tmp = fs32_to_cpu(sb, *p);
if (!tmp)
continue;
- for (j = 0; j < uspi->s_fpb; j++) {
- bh = sb_find_get_block(sb, tmp + j);
- if ((bh && DATA_BUFFER_USED(bh)) || tmp != fs32_to_cpu(sb, *p)) {
- retry = 1;
- brelse (bh);
- goto next2;
- }
- bforget (bh);
- }
+
*p = 0;
inode->i_blocks -= uspi->s_nspb;
mark_inode_dirty(inode);
@@ -162,7 +148,6 @@ next1:
frag_to_free = tmp;
free_count = uspi->s_fpb;
}
-next2:;
}
if (free_count > 0)
@@ -179,15 +164,7 @@ next2:;
if (!tmp )
ufs_panic(sb, "ufs_truncate_direct", "internal error");
frag4 = ufs_fragnum (frag4);
- for (j = 0; j < frag4; j++) {
- bh = sb_find_get_block (sb, tmp + j);
- if ((bh && DATA_BUFFER_USED(bh)) || tmp != fs32_to_cpu(sb, *p)) {
- retry = 1;
- brelse (bh);
- goto next1;
- }
- bforget (bh);
- }
+
*p = 0;
inode->i_blocks -= frag4 << uspi->s_nspfshift;
mark_inode_dirty(inode);
@@ -204,9 +181,8 @@ static int ufs_trunc_indirect (struct inode * inode, unsigned offset, __fs32 *p)
struct super_block * sb;
struct ufs_sb_private_info * uspi;
struct ufs_buffer_head * ind_ubh;
- struct buffer_head * bh;
__fs32 * ind;
- unsigned indirect_block, i, j, tmp;
+ unsigned indirect_block, i, tmp;
unsigned frag_to_free, free_count;
int retry;
@@ -238,15 +214,7 @@ static int ufs_trunc_indirect (struct inode * inode, unsigned offset, __fs32 *p)
tmp = fs32_to_cpu(sb, *ind);
if (!tmp)
continue;
- for (j = 0; j < uspi->s_fpb; j++) {
- bh = sb_find_get_block(sb, tmp + j);
- if ((bh && DATA_BUFFER_USED(bh)) || tmp != fs32_to_cpu(sb, *ind)) {
- retry = 1;
- brelse (bh);
- goto next;
- }
- bforget (bh);
- }
+
*ind = 0;
ubh_mark_buffer_dirty(ind_ubh);
if (free_count == 0) {
@@ -261,7 +229,6 @@ static int ufs_trunc_indirect (struct inode * inode, unsigned offset, __fs32 *p)
}
inode->i_blocks -= uspi->s_nspb;
mark_inode_dirty(inode);
-next:;
}
if (free_count > 0) {
@@ -430,9 +397,7 @@ void ufs_truncate (struct inode * inode)
struct ufs_inode_info *ufsi = UFS_I(inode);
struct super_block * sb;
struct ufs_sb_private_info * uspi;
- struct buffer_head * bh;
- unsigned offset;
- int err, retry;
+ int retry;
UFSD(("ENTER\n"))
sb = inode->i_sb;
@@ -442,6 +407,9 @@ void ufs_truncate (struct inode * inode)
return;
if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
return;
+
+ block_truncate_page(inode->i_mapping, inode->i_size, ufs_getfrag_block);
+
lock_kernel();
while (1) {
retry = ufs_trunc_direct(inode);
@@ -457,15 +425,7 @@ void ufs_truncate (struct inode * inode)
blk_run_address_space(inode->i_mapping);
yield();
}
- offset = inode->i_size & uspi->s_fshift;
- if (offset) {
- bh = ufs_bread (inode, inode->i_size >> uspi->s_fshift, 0, &err);
- if (bh) {
- memset (bh->b_data + offset, 0, uspi->s_fsize - offset);
- mark_buffer_dirty (bh);
- brelse (bh);
- }
- }
+
inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
ufsi->i_lastfrag = DIRECT_FRAGMENT;
unlock_kernel();
diff --git a/include/asm-arm/arch-s3c2410/hardware.h b/include/asm-arm/arch-s3c2410/hardware.h
index 1c9de29cafe..a2330bf8369 100644
--- a/include/asm-arm/arch-s3c2410/hardware.h
+++ b/include/asm-arm/arch-s3c2410/hardware.h
@@ -17,6 +17,7 @@
* 14-Sep-2004 BJD Added misccr and getpin to gpio
* 01-Oct-2004 BJD Added the new gpio functions
* 16-Oct-2004 BJD Removed the clock variables
+ * 15-Jan-2006 LCVR Added s3c2400_gpio_getirq()
*/
#ifndef __ASM_ARCH_HARDWARE_H
@@ -55,6 +56,12 @@ extern unsigned int s3c2410_gpio_getcfg(unsigned int pin);
extern int s3c2410_gpio_getirq(unsigned int pin);
+#ifdef CONFIG_CPU_S3C2400
+
+extern int s3c2400_gpio_getirq(unsigned int pin);
+
+#endif /* CONFIG_CPU_S3C2400 */
+
/* s3c2410_gpio_irqfilter
*
* set the irq filtering on the given pin
diff --git a/include/asm-arm/arch-s3c2410/regs-gpio.h b/include/asm-arm/arch-s3c2410/regs-gpio.h
index 7f1be48ad67..9697f93afe7 100644
--- a/include/asm-arm/arch-s3c2410/regs-gpio.h
+++ b/include/asm-arm/arch-s3c2410/regs-gpio.h
@@ -22,6 +22,7 @@
* 28-Mar-2005 LCVR Fixed definition of GPB10
* 26-Oct-2005 BJD Added generic configuration types
* 27-Nov-2005 LCVR Added definitions to S3C2400 registers
+ * 15-Jan-2006 LCVR Written S3C24XX_GPIO_BASE() macro
*/
@@ -39,6 +40,27 @@
#define S3C2410_GPIO_BANKG (32*6)
#define S3C2410_GPIO_BANKH (32*7)
+#ifdef CONFIG_CPU_S3C2400
+#define S3C24XX_GPIO_BASE(x) S3C2400_GPIO_BASE(x)
+#define S3C24XX_MISCCR S3C2400_MISCCR
+#else
+#define S3C24XX_GPIO_BASE(x) S3C2410_GPIO_BASE(x)
+#define S3C24XX_MISCCR S3C2410_MISCCR
+#endif /* CONFIG_CPU_S3C2400 */
+
+
+/* S3C2400 doesn't have a 1:1 mapping to S3C2410 gpio base pins */
+
+#define S3C2400_BANKNUM(pin) (((pin) & ~31) / 32)
+#define S3C2400_BASEA2B(pin) ((((pin) & ~31) >> 2))
+#define S3C2400_BASEC2H(pin) ((S3C2400_BANKNUM(pin) * 10) + \
+ (2 * (S3C2400_BANKNUM(pin)-2)))
+
+#define S3C2400_GPIO_BASE(pin) (pin < S3C2410_GPIO_BANKC ? \
+ S3C2400_BASEA2B(pin)+S3C24XX_VA_GPIO : \
+ S3C2400_BASEC2H(pin)+S3C24XX_VA_GPIO)
+
+
#define S3C2410_GPIO_BASE(pin) ((((pin) & ~31) >> 1) + S3C24XX_VA_GPIO)
#define S3C2410_GPIO_OFFSET(pin) ((pin) & 31)
diff --git a/include/asm-arm/checksum.h b/include/asm-arm/checksum.h
index d4256d5f3a7..747bdd31a74 100644
--- a/include/asm-arm/checksum.h
+++ b/include/asm-arm/checksum.h
@@ -77,7 +77,7 @@ ip_fast_csum(unsigned char * iph, unsigned int ihl)
mov %0, %0, lsr #16"
: "=r" (sum), "=r" (iph), "=r" (ihl), "=r" (tmp1)
: "1" (iph), "2" (ihl)
- : "cc");
+ : "cc", "memory");
return sum;
}
diff --git a/include/asm-cris/bitops.h b/include/asm-cris/bitops.h
index d3eb0f1e420..b7fef1572dc 100644
--- a/include/asm-cris/bitops.h
+++ b/include/asm-cris/bitops.h
@@ -290,7 +290,7 @@ static inline int find_next_zero_bit (const unsigned long * addr, int size, int
tmp = *p;
found_first:
- tmp |= ~0UL >> size;
+ tmp |= ~0UL << size;
found_middle:
return result + ffz(tmp);
}
diff --git a/include/asm-frv/bitops.h b/include/asm-frv/bitops.h
index 02be7b3a8a8..f686b519878 100644
--- a/include/asm-frv/bitops.h
+++ b/include/asm-frv/bitops.h
@@ -209,7 +209,7 @@ static inline int find_next_zero_bit(const void *addr, int size, int offset)
tmp = *p;
found_first:
- tmp |= ~0UL >> size;
+ tmp |= ~0UL << size;
found_middle:
return result + ffz(tmp);
}
diff --git a/include/asm-h8300/bitops.h b/include/asm-h8300/bitops.h
index c0411ec9d65..ff7c2b72159 100644
--- a/include/asm-h8300/bitops.h
+++ b/include/asm-h8300/bitops.h
@@ -227,7 +227,7 @@ static __inline__ int find_next_zero_bit (const unsigned long * addr, int size,
tmp = *p;
found_first:
- tmp |= ~0UL >> size;
+ tmp |= ~0UL << size;
found_middle:
return result + ffz(tmp);
}
diff --git a/include/asm-i386/system.h b/include/asm-i386/system.h
index 36a92ed6a9d..399145a247f 100644
--- a/include/asm-i386/system.h
+++ b/include/asm-i386/system.h
@@ -507,7 +507,7 @@ struct alt_instr {
#define smp_rmb() rmb()
#define smp_wmb() wmb()
#define smp_read_barrier_depends() read_barrier_depends()
-#define set_mb(var, value) do { xchg(&var, value); } while (0)
+#define set_mb(var, value) do { (void) xchg(&var, value); } while (0)
#else
#define smp_mb() barrier()
#define smp_rmb() barrier()
diff --git a/include/asm-i386/topology.h b/include/asm-i386/topology.h
index d7e19eb344b..af503a122b2 100644
--- a/include/asm-i386/topology.h
+++ b/include/asm-i386/topology.h
@@ -27,6 +27,15 @@
#ifndef _ASM_I386_TOPOLOGY_H
#define _ASM_I386_TOPOLOGY_H
+#ifdef CONFIG_SMP
+#define topology_physical_package_id(cpu) \
+ (phys_proc_id[cpu] == BAD_APICID ? -1 : phys_proc_id[cpu])
+#define topology_core_id(cpu) \
+ (cpu_core_id[cpu] == BAD_APICID ? 0 : cpu_core_id[cpu])
+#define topology_core_siblings(cpu) (cpu_core_map[cpu])
+#define topology_thread_siblings(cpu) (cpu_sibling_map[cpu])
+#endif
+
#ifdef CONFIG_NUMA
#include <asm/mpspec.h>
diff --git a/include/asm-ia64/ide.h b/include/asm-ia64/ide.h
index e62b95301d5..93f45c5f189 100644
--- a/include/asm-ia64/ide.h
+++ b/include/asm-ia64/ide.h
@@ -17,14 +17,6 @@
#include <linux/irq.h>
-#ifndef MAX_HWIFS
-# ifdef CONFIG_PCI
-#define MAX_HWIFS 10
-# else
-#define MAX_HWIFS 6
-# endif
-#endif
-
#define IDE_ARCH_OBSOLETE_DEFAULTS
static inline int ide_default_irq(unsigned long base)
diff --git a/include/asm-ia64/topology.h b/include/asm-ia64/topology.h
index 412ef8e493a..3ee19dfa46d 100644
--- a/include/asm-ia64/topology.h
+++ b/include/asm-ia64/topology.h
@@ -102,6 +102,13 @@ void build_cpu_to_node_map(void);
#endif /* CONFIG_NUMA */
+#ifdef CONFIG_SMP
+#define topology_physical_package_id(cpu) (cpu_data(cpu)->socket_id)
+#define topology_core_id(cpu) (cpu_data(cpu)->core_id)
+#define topology_core_siblings(cpu) (cpu_core_map[cpu])
+#define topology_thread_siblings(cpu) (cpu_sibling_map[cpu])
+#endif
+
#include <asm-generic/topology.h>
#endif /* _ASM_IA64_TOPOLOGY_H */
diff --git a/include/asm-parisc/atomic.h b/include/asm-parisc/atomic.h
index 2ca56d34aaa..4dc7253ff5d 100644
--- a/include/asm-parisc/atomic.h
+++ b/include/asm-parisc/atomic.h
@@ -1,9 +1,13 @@
+/* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>
+ * Copyright (C) 2006 Kyle McMartin <kyle@parisc-linux.org>
+ */
+
#ifndef _ASM_PARISC_ATOMIC_H_
#define _ASM_PARISC_ATOMIC_H_
#include <linux/config.h>
+#include <linux/types.h>
#include <asm/system.h>
-/* Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org>. */
/*
* Atomic operations that C can't guarantee us. Useful for
@@ -46,15 +50,6 @@ extern raw_spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned;
# define _atomic_spin_unlock_irqrestore(l,f) do { local_irq_restore(f); } while (0)
#endif
-/* Note that we need not lock read accesses - aligned word writes/reads
- * are atomic, so a reader never sees unconsistent values.
- *
- * Cache-line alignment would conflict with, for example, linux/module.h
- */
-
-typedef struct { volatile int counter; } atomic_t;
-
-
/* This should get optimized out since it's never called.
** Or get a link error if xchg is used "wrong".
*/
@@ -69,10 +64,9 @@ extern unsigned long __xchg64(unsigned long, unsigned long *);
#endif
/* optimizer better get rid of switch since size is a constant */
-static __inline__ unsigned long __xchg(unsigned long x, __volatile__ void * ptr,
- int size)
+static __inline__ unsigned long
+__xchg(unsigned long x, __volatile__ void * ptr, int size)
{
-
switch(size) {
#ifdef __LP64__
case 8: return __xchg64(x,(unsigned long *) ptr);
@@ -129,7 +123,13 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new_, int size)
(unsigned long)_n_, sizeof(*(ptr))); \
})
+/* Note that we need not lock read accesses - aligned word writes/reads
+ * are atomic, so a reader never sees unconsistent values.
+ *
+ * Cache-line alignment would conflict with, for example, linux/module.h
+ */
+typedef struct { volatile int counter; } atomic_t;
/* It's possible to reduce all atomic operations to either
* __atomic_add_return, atomic_set and atomic_read (the latter
@@ -210,12 +210,66 @@ static __inline__ int atomic_read(const atomic_t *v)
#define atomic_dec_and_test(v) (atomic_dec_return(v) == 0)
-#define ATOMIC_INIT(i) { (i) }
+#define ATOMIC_INIT(i) ((atomic_t) { (i) })
#define smp_mb__before_atomic_dec() smp_mb()
#define smp_mb__after_atomic_dec() smp_mb()
#define smp_mb__before_atomic_inc() smp_mb()
#define smp_mb__after_atomic_inc() smp_mb()
+#ifdef __LP64__
+
+typedef struct { volatile s64 counter; } atomic64_t;
+
+#define ATOMIC64_INIT(i) ((atomic64_t) { (i) })
+
+static __inline__ int
+__atomic64_add_return(s64 i, atomic64_t *v)
+{
+ int ret;
+ unsigned long flags;
+ _atomic_spin_lock_irqsave(v, flags);
+
+ ret = (v->counter += i);
+
+ _atomic_spin_unlock_irqrestore(v, flags);
+ return ret;
+}
+
+static __inline__ void
+atomic64_set(atomic64_t *v, s64 i)
+{
+ unsigned long flags;
+ _atomic_spin_lock_irqsave(v, flags);
+
+ v->counter = i;
+
+ _atomic_spin_unlock_irqrestore(v, flags);
+}
+
+static __inline__ s64
+atomic64_read(const atomic64_t *v)
+{
+ return v->counter;
+}
+
+#define atomic64_add(i,v) ((void)(__atomic64_add_return( ((s64)i),(v))))
+#define atomic64_sub(i,v) ((void)(__atomic64_add_return(-((s64)i),(v))))
+#define atomic64_inc(v) ((void)(__atomic64_add_return( 1,(v))))
+#define atomic64_dec(v) ((void)(__atomic64_add_return( -1,(v))))
+
+#define atomic64_add_return(i,v) (__atomic64_add_return( ((s64)i),(v)))
+#define atomic64_sub_return(i,v) (__atomic64_add_return(-((s64)i),(v)))
+#define atomic64_inc_return(v) (__atomic64_add_return( 1,(v)))
+#define atomic64_dec_return(v) (__atomic64_add_return( -1,(v)))
+
+#define atomic64_add_negative(a, v) (atomic64_add_return((a), (v)) < 0)
+
+#define atomic64_inc_and_test(v) (atomic64_inc_return(v) == 0)
+#define atomic64_dec_and_test(v) (atomic64_dec_return(v) == 0)
+
+#endif /* __LP64__ */
+
#include <asm-generic/atomic.h>
-#endif
+
+#endif /* _ASM_PARISC_ATOMIC_H_ */
diff --git a/include/asm-parisc/cacheflush.h b/include/asm-parisc/cacheflush.h
index 1bc3c83ee74..c53af9ff41b 100644
--- a/include/asm-parisc/cacheflush.h
+++ b/include/asm-parisc/cacheflush.h
@@ -183,4 +183,10 @@ flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr, unsigned long
__flush_cache_page(vma, vmaddr);
}
+
+#ifdef CONFIG_DEBUG_RODATA
+void mark_rodata_ro(void);
#endif
+
+#endif /* _PARISC_CACHEFLUSH_H */
+
diff --git a/include/asm-parisc/compat_ucontext.h b/include/asm-parisc/compat_ucontext.h
index a1228a3d207..2f7292afde3 100644
--- a/include/asm-parisc/compat_ucontext.h
+++ b/include/asm-parisc/compat_ucontext.h
@@ -1,8 +1,7 @@
#ifndef _ASM_PARISC_COMPAT_UCONTEXT_H
#define _ASM_PARISC_COMPAT_UCONTEXT_H
-#include<linux/compat.h>
-#include<asm/compat_signal.h>
+#include <linux/compat.h>
/* 32-bit ucontext as seen from an 64-bit kernel */
struct compat_ucontext {
diff --git a/include/asm-parisc/grfioctl.h b/include/asm-parisc/grfioctl.h
index 6a910311b56..671e06042b4 100644
--- a/include/asm-parisc/grfioctl.h
+++ b/include/asm-parisc/grfioctl.h
@@ -58,7 +58,7 @@
#define CRT_ID_ELK_1024DB 0x27849CA5 /* Elk 1024x768 double buffer */
#define CRT_ID_ELK_GS S9000_ID_A1924A /* Elk 1280x1024 GreyScale */
#define CRT_ID_CRX24 S9000_ID_A1439A /* Piranha */
-#define CRT_ID_VISUALIZE_EG 0x2D08C0A7 /* Graffiti (built-in B132+/B160L) */
+#define CRT_ID_VISUALIZE_EG 0x2D08C0A7 /* Graffiti, A4450A (built-in B132+/B160L) */
#define CRT_ID_THUNDER 0x2F23E5FC /* Thunder 1 VISUALIZE 48*/
#define CRT_ID_THUNDER2 0x2F8D570E /* Thunder 2 VISUALIZE 48 XP*/
#define CRT_ID_HCRX S9000_ID_HCRX /* Hyperdrive HCRX */
diff --git a/include/asm-parisc/pci.h b/include/asm-parisc/pci.h
index f277254159b..fe7f6a2f5aa 100644
--- a/include/asm-parisc/pci.h
+++ b/include/asm-parisc/pci.h
@@ -18,6 +18,18 @@
*/
#define PCI_MAX_BUSSES 256
+
+/* To be used as: mdelay(pci_post_reset_delay);
+ *
+ * post_reset is the time the kernel should stall to prevent anyone from
+ * accessing the PCI bus once #RESET is de-asserted.
+ * PCI spec somewhere says 1 second but with multi-PCI bus systems,
+ * this makes the boot time much longer than necessary.
+ * 20ms seems to work for all the HP PCI implementations to date.
+ */
+#define pci_post_reset_delay 50
+
+
/*
** pci_hba_data (aka H2P_OBJECT in HP/UX)
**
@@ -83,7 +95,7 @@ static __inline__ int pci_is_lmmio(struct pci_hba_data *hba, unsigned long a)
/*
** Convert between PCI (IO_VIEW) addresses and processor (PA_VIEW) addresses.
-** See pcibios.c for more conversions used by Generic PCI code.
+** See pci.c for more conversions used by Generic PCI code.
**
** Platform characteristics/firmware guarantee that
** (1) PA_VIEW - IO_VIEW = lmmio_offset for both LMMIO and ELMMIO
@@ -191,9 +203,6 @@ struct pci_bios_ops {
*/
extern struct pci_port_ops *pci_port;
extern struct pci_bios_ops *pci_bios;
-extern int pci_post_reset_delay; /* delay after de-asserting #RESET */
-extern int pci_hba_count;
-extern struct pci_hba_data *parisc_pci_hba[];
#ifdef CONFIG_PCI
extern void pcibios_register_hba(struct pci_hba_data *);
diff --git a/include/asm-parisc/pgalloc.h b/include/asm-parisc/pgalloc.h
index 6291d6692e5..3122fad38a1 100644
--- a/include/asm-parisc/pgalloc.h
+++ b/include/asm-parisc/pgalloc.h
@@ -137,7 +137,6 @@ static inline void pte_free_kernel(pte_t *pte)
#define pte_free(page) pte_free_kernel(page_address(page))
-extern int do_check_pgt_cache(int, int);
#define check_pgt_cache() do { } while (0)
#endif
diff --git a/include/asm-parisc/pgtable.h b/include/asm-parisc/pgtable.h
index b4554711c3e..4e34c6b4405 100644
--- a/include/asm-parisc/pgtable.h
+++ b/include/asm-parisc/pgtable.h
@@ -213,7 +213,7 @@ extern void *vmalloc_start;
#define PAGE_COPY PAGE_EXECREAD
#define PAGE_RWX __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_WRITE | _PAGE_EXEC |_PAGE_ACCESSED)
#define PAGE_KERNEL __pgprot(_PAGE_KERNEL)
-#define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_EXEC | _PAGE_READ | _PAGE_DIRTY | _PAGE_ACCESSED)
+#define PAGE_KERNEL_RO __pgprot(_PAGE_KERNEL & ~_PAGE_WRITE)
#define PAGE_KERNEL_UNC __pgprot(_PAGE_KERNEL | _PAGE_NO_CACHE)
#define PAGE_GATEWAY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED | _PAGE_GATEWAY| _PAGE_READ)
#define PAGE_FLUSH __pgprot(_PAGE_FLUSH)
diff --git a/include/asm-parisc/rt_sigframe.h b/include/asm-parisc/rt_sigframe.h
index 5623c032b64..f0dd3b30f6c 100644
--- a/include/asm-parisc/rt_sigframe.h
+++ b/include/asm-parisc/rt_sigframe.h
@@ -1,10 +1,6 @@
#ifndef _ASM_PARISC_RT_SIGFRAME_H
#define _ASM_PARISC_RT_SIGFRAME_H
-#ifdef CONFIG_COMPAT
-#include <asm/compat_rt_sigframe.h>
-#endif
-
#define SIGRETURN_TRAMP 4
#define SIGRESTARTBLOCK_TRAMP 5
#define TRAMP_SIZE (SIGRETURN_TRAMP + SIGRESTARTBLOCK_TRAMP)
diff --git a/include/asm-parisc/unistd.h b/include/asm-parisc/unistd.h
index 80b7b98c70a..c56fccbf34a 100644
--- a/include/asm-parisc/unistd.h
+++ b/include/asm-parisc/unistd.h
@@ -761,8 +761,27 @@
#define __NR_keyctl (__NR_Linux + 266)
#define __NR_ioprio_set (__NR_Linux + 267)
#define __NR_ioprio_get (__NR_Linux + 268)
+#define __NR_inotify_init (__NR_Linux + 269)
+#define __NR_inotify_add_watch (__NR_Linux + 270)
+#define __NR_inotify_rm_watch (__NR_Linux + 271)
+#define __NR_migrate_pages (__NR_Linux + 272)
+#define __NR_pselect6 (__NR_Linux + 273)
+#define __NR_ppoll (__NR_Linux + 274)
+#define __NR_openat (__NR_Linux + 275)
+#define __NR_mkdirat (__NR_Linux + 276)
+#define __NR_mknodat (__NR_Linux + 277)
+#define __NR_fchownat (__NR_Linux + 278)
+#define __NR_futimesat (__NR_Linux + 279)
+#define __NR_newfstatat (__NR_Linux + 280)
+#define __NR_unlinkat (__NR_Linux + 281)
+#define __NR_renameat (__NR_Linux + 282)
+#define __NR_linkat (__NR_Linux + 283)
+#define __NR_symlinkat (__NR_Linux + 284)
+#define __NR_readlinkat (__NR_Linux + 285)
+#define __NR_fchmodat (__NR_Linux + 286)
+#define __NR_faccessat (__NR_Linux + 287)
-#define __NR_Linux_syscalls 269
+#define __NR_Linux_syscalls 288
#define HPUX_GATEWAY_ADDR 0xC0000004
#define LINUX_GATEWAY_ADDR 0x100
diff --git a/include/asm-s390/dasd.h b/include/asm-s390/dasd.h
index 1630c26e8f4..c744ff33b1d 100644
--- a/include/asm-s390/dasd.h
+++ b/include/asm-s390/dasd.h
@@ -204,7 +204,8 @@ typedef struct attrib_data_t {
*
* Here ist how the ioctl-nr should be used:
* 0 - 31 DASD driver itself
- * 32 - 239 still open
+ * 32 - 229 still open
+ * 230 - 239 DASD extended error reporting
* 240 - 255 reserved for EMC
*******************************************************************************/
@@ -236,12 +237,22 @@ typedef struct attrib_data_t {
#define BIODASDPSRD _IOR(DASD_IOCTL_LETTER,4,dasd_rssd_perf_stats_t)
/* Get Attributes (cache operations) */
#define BIODASDGATTR _IOR(DASD_IOCTL_LETTER,5,attrib_data_t)
+/* retrieve extended error-reporting value */
+#define BIODASDEERGET _IOR(DASD_IOCTL_LETTER,6,int)
/* #define BIODASDFORMAT _IOW(IOCTL_LETTER,0,format_data_t) , deprecated */
#define BIODASDFMT _IOW(DASD_IOCTL_LETTER,1,format_data_t)
/* Set Attributes (cache operations) */
#define BIODASDSATTR _IOW(DASD_IOCTL_LETTER,2,attrib_data_t)
+/* retrieve extended error-reporting value */
+#define BIODASDEERSET _IOW(DASD_IOCTL_LETTER,3,int)
+
+
+/* remove all records from the eer buffer */
+#define DASD_EER_PURGE _IO(DASD_IOCTL_LETTER,230)
+/* set the number of pages that are used for the internal eer buffer */
+#define DASD_EER_SETBUFSIZE _IOW(DASD_IOCTL_LETTER,230,int)
#endif /* DASD_H */
diff --git a/include/asm-s390/io.h b/include/asm-s390/io.h
index 71f55eb2350..b05825dd16d 100644
--- a/include/asm-s390/io.h
+++ b/include/asm-s390/io.h
@@ -90,10 +90,16 @@ extern void iounmap(void *addr);
#define readb_relaxed(addr) readb(addr)
#define readw_relaxed(addr) readw(addr)
#define readl_relaxed(addr) readl(addr)
+#define __raw_readb readb
+#define __raw_readw readw
+#define __raw_readl readl
#define writeb(b,addr) (*(volatile unsigned char *) __io_virt(addr) = (b))
#define writew(b,addr) (*(volatile unsigned short *) __io_virt(addr) = (b))
#define writel(b,addr) (*(volatile unsigned int *) __io_virt(addr) = (b))
+#define __raw_writeb writeb
+#define __raw_writew writew
+#define __raw_writel writel
#define memset_io(a,b,c) memset(__io_virt(a),(b),(c))
#define memcpy_fromio(a,b,c) memcpy((a),__io_virt(b),(c))
diff --git a/include/asm-s390/timer.h b/include/asm-s390/timer.h
index ea0788967c5..fcd6c256a2d 100644
--- a/include/asm-s390/timer.h
+++ b/include/asm-s390/timer.h
@@ -1,7 +1,7 @@
/*
* include/asm-s390/timer.h
*
- * (C) Copyright IBM Corp. 2003
+ * (C) Copyright IBM Corp. 2003,2006
* Virtual CPU timer
*
* Author: Jan Glauber (jang@de.ibm.com)
@@ -10,6 +10,8 @@
#ifndef _ASM_S390_TIMER_H
#define _ASM_S390_TIMER_H
+#ifdef __KERNEL__
+
#include <linux/timer.h>
#define VTIMER_MAX_SLICE (0x7ffffffffffff000LL)
@@ -43,4 +45,6 @@ extern void add_virt_timer_periodic(void *new);
extern int mod_virt_timer(struct vtimer_list *timer, __u64 expires);
extern int del_virt_timer(struct vtimer_list *timer);
-#endif
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_S390_TIMER_H */
diff --git a/include/asm-v850/bitops.h b/include/asm-v850/bitops.h
index 8955d2376ac..609b9e87222 100644
--- a/include/asm-v850/bitops.h
+++ b/include/asm-v850/bitops.h
@@ -188,7 +188,7 @@ static inline int find_next_zero_bit(const void *addr, int size, int offset)
tmp = *p;
found_first:
- tmp |= ~0UL >> size;
+ tmp |= ~0UL << size;
found_middle:
return result + ffz (tmp);
}
diff --git a/include/asm-x86_64/apic.h b/include/asm-x86_64/apic.h
index 4f6a4dc455b..bdbd8935612 100644
--- a/include/asm-x86_64/apic.h
+++ b/include/asm-x86_64/apic.h
@@ -17,6 +17,7 @@
#define APIC_DEBUG 2
extern int apic_verbosity;
+extern int apic_runs_main_timer;
/*
* Define the default level of output to be very little
diff --git a/include/asm-x86_64/cpufeature.h b/include/asm-x86_64/cpufeature.h
index 41c0ac8559b..76bb6193ae9 100644
--- a/include/asm-x86_64/cpufeature.h
+++ b/include/asm-x86_64/cpufeature.h
@@ -61,7 +61,7 @@
#define X86_FEATURE_K6_MTRR (3*32+ 1) /* AMD K6 nonstandard MTRRs */
#define X86_FEATURE_CYRIX_ARR (3*32+ 2) /* Cyrix ARRs (= MTRRs) */
#define X86_FEATURE_CENTAUR_MCR (3*32+ 3) /* Centaur MCRs (= MTRRs) */
-/* 4 free */
+#define X86_FEATURE_REP_GOOD (3*32+ 4) /* rep microcode works well on this CPU */
#define X86_FEATURE_CONSTANT_TSC (3*32+5) /* TSC runs at constant rate */
#define X86_FEATURE_SYNC_RDTSC (3*32+6) /* RDTSC syncs CPU core */
diff --git a/include/asm-x86_64/hardirq.h b/include/asm-x86_64/hardirq.h
index 8661b476fb4..8689951e350 100644
--- a/include/asm-x86_64/hardirq.h
+++ b/include/asm-x86_64/hardirq.h
@@ -16,23 +16,6 @@
#define set_softirq_pending(x) write_pda(__softirq_pending, (x))
#define or_softirq_pending(x) or_pda(__softirq_pending, (x))
-/*
- * 'what should we do if we get a hw irq event on an illegal vector'.
- * each architecture has to answer this themselves.
- */
-static inline void ack_bad_irq(unsigned int irq)
-{
- printk("unexpected IRQ trap at vector %02x\n", irq);
-#ifdef CONFIG_X86_LOCAL_APIC
- /*
- * Currently unexpected vectors happen only on SMP and APIC.
- * We _must_ ack these because every local APIC has only N
- * irq slots per priority level, and a 'hanging, unacked' IRQ
- * holds up an irq slot - in excessive cases (when multiple
- * unexpected vectors occur) that might lock up the APIC
- * completely.
- */
- ack_APIC_irq();
-#endif
-}
+extern void ack_bad_irq(unsigned int irq);
+
#endif /* __ASM_HARDIRQ_H */
diff --git a/include/asm-x86_64/kexec.h b/include/asm-x86_64/kexec.h
index ae28cd44bcd..c564bae0343 100644
--- a/include/asm-x86_64/kexec.h
+++ b/include/asm-x86_64/kexec.h
@@ -1,8 +1,9 @@
#ifndef _X86_64_KEXEC_H
#define _X86_64_KEXEC_H
+#include <linux/string.h>
+
#include <asm/page.h>
-#include <asm/proto.h>
#include <asm/ptrace.h>
/*
diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h
index 115e496c613..c99832e7bf3 100644
--- a/include/asm-x86_64/proto.h
+++ b/include/asm-x86_64/proto.h
@@ -41,10 +41,18 @@ extern void iommu_hole_init(void);
extern void time_init_gtod(void);
extern int pmtimer_mark_offset(void);
+extern void pmtimer_resume(void);
+extern void pmtimer_wait(unsigned);
extern unsigned int do_gettimeoffset_pm(void);
+#ifdef CONFIG_X86_PM_TIMER
extern u32 pmtmr_ioport;
+#else
+#define pmtmr_ioport 0
+#endif
extern unsigned long long monotonic_base;
extern int sysctl_vsyscall;
+extern int nohpet;
+extern unsigned long vxtime_hz;
extern void do_softirq_thunk(void);
@@ -65,6 +73,9 @@ extern void free_bootmem_generic(unsigned long phys, unsigned len);
extern void load_gs_index(unsigned gs);
+extern void stop_timer_interrupt(void);
+extern void main_timer_handler(struct pt_regs *regs);
+
extern unsigned long end_pfn_map;
extern void show_trace(unsigned long * rsp);
diff --git a/include/asm-x86_64/system.h b/include/asm-x86_64/system.h
index a73f0c789d8..b7f66034ae7 100644
--- a/include/asm-x86_64/system.h
+++ b/include/asm-x86_64/system.h
@@ -327,7 +327,7 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
#define wmb() asm volatile("" ::: "memory")
#endif
#define read_barrier_depends() do {} while(0)
-#define set_mb(var, value) do { xchg(&var, value); } while (0)
+#define set_mb(var, value) do { (void) xchg(&var, value); } while (0)
#define set_wmb(var, value) do { var = value; wmb(); } while (0)
#define warn_if_not_ulong(x) do { unsigned long foo; (void) (&(x) == &foo); } while (0)
diff --git a/include/asm-x86_64/topology.h b/include/asm-x86_64/topology.h
index 2fa7f27381b..c642f5d9882 100644
--- a/include/asm-x86_64/topology.h
+++ b/include/asm-x86_64/topology.h
@@ -57,6 +57,15 @@ extern int __node_distance(int, int);
#endif
+#ifdef CONFIG_SMP
+#define topology_physical_package_id(cpu) \
+ (phys_proc_id[cpu] == BAD_APICID ? -1 : phys_proc_id[cpu])
+#define topology_core_id(cpu) \
+ (cpu_core_id[cpu] == BAD_APICID ? 0 : cpu_core_id[cpu])
+#define topology_core_siblings(cpu) (cpu_core_map[cpu])
+#define topology_thread_siblings(cpu) (cpu_sibling_map[cpu])
+#endif
+
#include <asm-generic/topology.h>
#endif
diff --git a/include/linux/bitops.h b/include/linux/bitops.h
index 6a2a19f14bb..208650b1ad3 100644
--- a/include/linux/bitops.h
+++ b/include/linux/bitops.h
@@ -81,7 +81,7 @@ static inline int generic_fls64(__u64 x)
{
__u32 h = x >> 32;
if (h)
- return fls(x) + 32;
+ return fls(h) + 32;
return fls(x);
}
diff --git a/include/linux/configfs.h b/include/linux/configfs.h
index acffb8c9073..a7f01502753 100644
--- a/include/linux/configfs.h
+++ b/include/linux/configfs.h
@@ -126,7 +126,7 @@ extern struct config_item *config_group_find_obj(struct config_group *, const ch
struct configfs_attribute {
- char *ca_name;
+ const char *ca_name;
struct module *ca_owner;
mode_t ca_mode;
};
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index a3ed5e059d4..a3f09947940 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -108,7 +108,9 @@ struct dentry {
struct dentry_operations *d_op;
struct super_block *d_sb; /* The root of the dentry tree */
void *d_fsdata; /* fs-specific data */
+#ifdef CONFIG_PROFILING
struct dcookie_struct *d_cookie; /* cookie, if any */
+#endif
int d_mounted;
unsigned char d_iname[DNAME_INLINE_LEN_MIN]; /* small names */
};
diff --git a/include/linux/elfcore.h b/include/linux/elfcore.h
index dbd7bb4a33b..0cf0bea010f 100644
--- a/include/linux/elfcore.h
+++ b/include/linux/elfcore.h
@@ -5,6 +5,7 @@
#include <linux/signal.h>
#include <linux/time.h>
#include <linux/user.h>
+#include <linux/ptrace.h>
struct elf_siginfo
{
diff --git a/include/linux/i2o.h b/include/linux/i2o.h
index 9ba80679666..5a9d8c59917 100644
--- a/include/linux/i2o.h
+++ b/include/linux/i2o.h
@@ -1115,9 +1115,11 @@ static inline struct i2o_message *i2o_msg_get(struct i2o_controller *c)
return ERR_PTR(-ENOMEM);
mmsg->mfa = readl(c->in_port);
- if (mmsg->mfa == I2O_QUEUE_EMPTY) {
+ if (unlikely(mmsg->mfa >= c->in_queue.len)) {
mempool_free(mmsg, c->in_msg.mempool);
- return ERR_PTR(-EBUSY);
+ if(mmsg->mfa == I2O_QUEUE_EMPTY)
+ return ERR_PTR(-EBUSY);
+ return ERR_PTR(-EFAULT);
}
return &mmsg->msg;
diff --git a/include/linux/ide.h b/include/linux/ide.h
index 110b3cfac02..a7fc4cc79b2 100644
--- a/include/linux/ide.h
+++ b/include/linux/ide.h
@@ -582,7 +582,6 @@ typedef struct ide_drive_s {
unsigned noprobe : 1; /* from: hdx=noprobe */
unsigned removable : 1; /* 1 if need to do check_media_change */
unsigned attach : 1; /* needed for removable devices */
- unsigned is_flash : 1; /* 1 if probed as flash */
unsigned forced_geom : 1; /* 1 if hdx=c,h,s was given at boot */
unsigned no_unmask : 1; /* disallow setting unmask bit */
unsigned no_io_32bit : 1; /* disallow enabling 32bit I/O */
@@ -1006,7 +1005,6 @@ extern ide_hwif_t ide_hwifs[]; /* master data repository */
extern int noautodma;
extern int ide_end_request (ide_drive_t *drive, int uptodate, int nrsecs);
-extern int __ide_end_request (ide_drive_t *drive, struct request *rq, int uptodate, int nrsecs);
/*
* This is used on exit from the driver to designate the next irq handler
diff --git a/include/linux/jbd.h b/include/linux/jbd.h
index 558cb4c26ec..751bb384946 100644
--- a/include/linux/jbd.h
+++ b/include/linux/jbd.h
@@ -23,6 +23,7 @@
#define jfs_debug jbd_debug
#else
+#include <linux/types.h>
#include <linux/buffer_head.h>
#include <linux/journal-head.h>
#include <linux/stddef.h>
@@ -618,6 +619,7 @@ struct transaction_s
* @j_wbuf: array of buffer_heads for journal_commit_transaction
* @j_wbufsize: maximum number of buffer_heads allowed in j_wbuf, the
* number that will fit in j_blocksize
+ * @j_last_sync_writer: most recent pid which did a synchronous write
* @j_private: An opaque pointer to fs-private information.
*/
@@ -807,6 +809,8 @@ struct journal_s
struct buffer_head **j_wbuf;
int j_wbufsize;
+ pid_t j_last_sync_writer;
+
/*
* An opaque pointer to fs-private information. ext3 puts its
* superblock pointer here
diff --git a/include/linux/kbd_kern.h b/include/linux/kbd_kern.h
index 45f625d7d0b..3aed37314ab 100644
--- a/include/linux/kbd_kern.h
+++ b/include/linux/kbd_kern.h
@@ -151,6 +151,11 @@ extern unsigned int keymap_count;
static inline void con_schedule_flip(struct tty_struct *t)
{
+ unsigned long flags;
+ spin_lock_irqsave(&t->buf.lock, flags);
+ if (t->buf.tail != NULL)
+ t->buf.tail->active = 0;
+ spin_unlock_irqrestore(&t->buf.lock, flags);
schedule_work(&t->buf.work);
}
diff --git a/include/linux/list.h b/include/linux/list.h
index 945daa1f13d..47208bd99f9 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -34,9 +34,11 @@ struct list_head {
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
-#define INIT_LIST_HEAD(ptr) do { \
- (ptr)->next = (ptr); (ptr)->prev = (ptr); \
-} while (0)
+static inline void INIT_LIST_HEAD(struct list_head *list)
+{
+ list->next = list;
+ list->prev = list;
+}
/*
* Insert a new entry between two known consecutive entries.
@@ -534,7 +536,11 @@ struct hlist_node {
#define HLIST_HEAD_INIT { .first = NULL }
#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
-#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL)
+static inline void INIT_HLIST_NODE(struct hlist_node *h)
+{
+ h->next = NULL;
+ h->pprev = NULL;
+}
static inline int hlist_unhashed(const struct hlist_node *h)
{
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index 95c8fea293b..920766cea79 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -84,6 +84,7 @@ struct nlm_rqst {
struct nlm_args a_args; /* arguments */
struct nlm_res a_res; /* result */
struct nlm_wait * a_block;
+ unsigned int a_retries; /* Retry count */
char a_owner[NLMCLNT_OHSIZE];
};
@@ -148,7 +149,6 @@ struct nlm_rqst * nlmclnt_alloc_call(void);
int nlmclnt_prepare_block(struct nlm_rqst *req, struct nlm_host *host, struct file_lock *fl);
void nlmclnt_finish_block(struct nlm_rqst *req);
long nlmclnt_block(struct nlm_rqst *req, long timeout);
-int nlmclnt_cancel(struct nlm_host *, struct file_lock *);
u32 nlmclnt_grant(struct nlm_lock *);
void nlmclnt_recovery(struct nlm_host *, u32);
int nlmclnt_reclaim(struct nlm_host *, struct file_lock *);
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index ccd3e13de1e..f38872abc12 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -21,24 +21,35 @@ struct mmc_command {
u32 arg;
u32 resp[4];
unsigned int flags; /* expected response type */
-#define MMC_RSP_NONE (0 << 0)
-#define MMC_RSP_SHORT (1 << 0)
-#define MMC_RSP_LONG (2 << 0)
-#define MMC_RSP_MASK (3 << 0)
-#define MMC_RSP_CRC (1 << 3) /* expect valid crc */
-#define MMC_RSP_BUSY (1 << 4) /* card may send busy */
-#define MMC_RSP_OPCODE (1 << 5) /* response contains opcode */
+#define MMC_RSP_PRESENT (1 << 0)
+#define MMC_RSP_136 (1 << 1) /* 136 bit response */
+#define MMC_RSP_CRC (1 << 2) /* expect valid crc */
+#define MMC_RSP_BUSY (1 << 3) /* card may send busy */
+#define MMC_RSP_OPCODE (1 << 4) /* response contains opcode */
+#define MMC_CMD_MASK (3 << 5) /* command type */
+#define MMC_CMD_AC (0 << 5)
+#define MMC_CMD_ADTC (1 << 5)
+#define MMC_CMD_BC (2 << 5)
+#define MMC_CMD_BCR (3 << 5)
/*
* These are the response types, and correspond to valid bit
* patterns of the above flags. One additional valid pattern
* is all zeros, which means we don't expect a response.
*/
-#define MMC_RSP_R1 (MMC_RSP_SHORT|MMC_RSP_CRC|MMC_RSP_OPCODE)
-#define MMC_RSP_R1B (MMC_RSP_SHORT|MMC_RSP_CRC|MMC_RSP_OPCODE|MMC_RSP_BUSY)
-#define MMC_RSP_R2 (MMC_RSP_LONG|MMC_RSP_CRC)
-#define MMC_RSP_R3 (MMC_RSP_SHORT)
-#define MMC_RSP_R6 (MMC_RSP_SHORT|MMC_RSP_CRC)
+#define MMC_RSP_NONE (0)
+#define MMC_RSP_R1 (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE)
+#define MMC_RSP_R1B (MMC_RSP_PRESENT|MMC_RSP_CRC|MMC_RSP_OPCODE|MMC_RSP_BUSY)
+#define MMC_RSP_R2 (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC)
+#define MMC_RSP_R3 (MMC_RSP_PRESENT)
+#define MMC_RSP_R6 (MMC_RSP_PRESENT|MMC_RSP_CRC)
+
+#define mmc_resp_type(cmd) ((cmd)->flags & (MMC_RSP_PRESENT|MMC_RSP_136|MMC_RSP_CRC|MMC_RSP_BUSY|MMC_RSP_OPCODE))
+
+/*
+ * These are the command types.
+ */
+#define mmc_cmd_type(cmd) ((cmd)->flags & MMC_CMD_TYPE)
unsigned int retries; /* max number of retries */
unsigned int error; /* command error */
diff --git a/include/linux/mmc/protocol.h b/include/linux/mmc/protocol.h
index a14dc306545..81c3f77f652 100644
--- a/include/linux/mmc/protocol.h
+++ b/include/linux/mmc/protocol.h
@@ -79,7 +79,7 @@
/* SD commands type argument response */
/* class 8 */
/* This is basically the same command as for MMC with some quirks. */
-#define SD_SEND_RELATIVE_ADDR 3 /* ac R6 */
+#define SD_SEND_RELATIVE_ADDR 3 /* bcr R6 */
/* Application commands */
#define SD_APP_SET_BUS_WIDTH 6 /* ac [1:0] bus width R1 */
diff --git a/include/linux/netfilter_ipv4/ipt_connbytes.h b/include/linux/netfilter_ipv4/ipt_connbytes.h
index b04dfa3083c..f63e6ee9111 100644
--- a/include/linux/netfilter_ipv4/ipt_connbytes.h
+++ b/include/linux/netfilter_ipv4/ipt_connbytes.h
@@ -1,10 +1,10 @@
#ifndef _IPT_CONNBYTES_H
#define _IPT_CONNBYTES_H
-#include <net/netfilter/xt_connbytes.h>
+#include <linux/netfilter/xt_connbytes.h>
#define ipt_connbytes_what xt_connbytes_what
-#define IPT_CONNBYTES_PKTS XT_CONNBYTES_PACKETS
+#define IPT_CONNBYTES_PKTS XT_CONNBYTES_PKTS
#define IPT_CONNBYTES_BYTES XT_CONNBYTES_BYTES
#define IPT_CONNBYTES_AVGPKT XT_CONNBYTES_AVGPKT
diff --git a/include/linux/netfilter_ipv4/ipt_policy.h b/include/linux/netfilter_ipv4/ipt_policy.h
index 7fd1bec453f..a3f6eff39d3 100644
--- a/include/linux/netfilter_ipv4/ipt_policy.h
+++ b/include/linux/netfilter_ipv4/ipt_policy.h
@@ -27,16 +27,22 @@ struct ipt_policy_spec
reqid:1;
};
+union ipt_policy_addr
+{
+ struct in_addr a4;
+ struct in6_addr a6;
+};
+
struct ipt_policy_elem
{
- u_int32_t saddr;
- u_int32_t smask;
- u_int32_t daddr;
- u_int32_t dmask;
- u_int32_t spi;
- u_int32_t reqid;
- u_int8_t proto;
- u_int8_t mode;
+ union ipt_policy_addr saddr;
+ union ipt_policy_addr smask;
+ union ipt_policy_addr daddr;
+ union ipt_policy_addr dmask;
+ u_int32_t spi;
+ u_int32_t reqid;
+ u_int8_t proto;
+ u_int8_t mode;
struct ipt_policy_spec match;
struct ipt_policy_spec invert;
diff --git a/include/linux/netfilter_ipv6/ip6t_policy.h b/include/linux/netfilter_ipv6/ip6t_policy.h
index 5a93afcd2ff..671bd818300 100644
--- a/include/linux/netfilter_ipv6/ip6t_policy.h
+++ b/include/linux/netfilter_ipv6/ip6t_policy.h
@@ -27,16 +27,22 @@ struct ip6t_policy_spec
reqid:1;
};
+union ip6t_policy_addr
+{
+ struct in_addr a4;
+ struct in6_addr a6;
+};
+
struct ip6t_policy_elem
{
- struct in6_addr saddr;
- struct in6_addr smask;
- struct in6_addr daddr;
- struct in6_addr dmask;
- u_int32_t spi;
- u_int32_t reqid;
- u_int8_t proto;
- u_int8_t mode;
+ union ip6t_policy_addr saddr;
+ union ip6t_policy_addr smask;
+ union ip6t_policy_addr daddr;
+ union ip6t_policy_addr dmask;
+ u_int32_t spi;
+ u_int32_t reqid;
+ u_int8_t proto;
+ u_int8_t mode;
struct ip6t_policy_spec match;
struct ip6t_policy_spec invert;
diff --git a/include/linux/parport.h b/include/linux/parport.h
index f67f838a3a1..008d736a6c9 100644
--- a/include/linux/parport.h
+++ b/include/linux/parport.h
@@ -128,6 +128,11 @@ struct amiga_parport_state {
unsigned char statusdir;/* ciab.ddrb & 7 */
};
+struct ip32_parport_state {
+ unsigned int dcr;
+ unsigned int ecr;
+};
+
struct parport_state {
union {
struct pc_parport_state pc;
@@ -135,6 +140,7 @@ struct parport_state {
struct ax_parport_state ax;
struct amiga_parport_state amiga;
/* Atari has not state. */
+ struct ip32_parport_state ip32;
void *misc;
} u;
};
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index b0b908f583c..92a619ba163 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1670,6 +1670,9 @@
#define PCI_DEVICE_ID_SIIG_2S1P_20x_550 0x2060
#define PCI_DEVICE_ID_SIIG_2S1P_20x_650 0x2061
#define PCI_DEVICE_ID_SIIG_2S1P_20x_850 0x2062
+#define PCI_DEVICE_ID_SIIG_8S_20x_550 0x2080
+#define PCI_DEVICE_ID_SIIG_8S_20x_650 0x2081
+#define PCI_DEVICE_ID_SIIG_8S_20x_850 0x2082
#define PCI_SUBDEVICE_ID_SIIG_QUARTET_SERIAL 0x2050
#define PCI_VENDOR_ID_RADISYS 0x1331
diff --git a/include/linux/pktcdvd.h b/include/linux/pktcdvd.h
index 2c177e4c8f2..8a94c717c26 100644
--- a/include/linux/pktcdvd.h
+++ b/include/linux/pktcdvd.h
@@ -114,7 +114,7 @@ struct pkt_ctrl_command {
struct packet_settings
{
- __u8 size; /* packet size in (512 byte) sectors */
+ __u32 size; /* packet size in (512 byte) sectors */
__u8 fp; /* fixed packets */
__u8 link_loss; /* the rest is specified
* as per Mt Fuji */
@@ -169,8 +169,8 @@ struct packet_iosched
#if (PAGE_SIZE % CD_FRAMESIZE) != 0
#error "PAGE_SIZE must be a multiple of CD_FRAMESIZE"
#endif
-#define PACKET_MAX_SIZE 32
-#define PAGES_PER_PACKET (PACKET_MAX_SIZE * CD_FRAMESIZE / PAGE_SIZE)
+#define PACKET_MAX_SIZE 128
+#define FRAMES_PER_PAGE (PAGE_SIZE / CD_FRAMESIZE)
#define PACKET_MAX_SECTORS (PACKET_MAX_SIZE * CD_FRAMESIZE >> 9)
enum packet_data_state {
@@ -219,7 +219,7 @@ struct packet_data
atomic_t io_errors; /* Number of read/write errors during IO */
struct bio *r_bios[PACKET_MAX_SIZE]; /* bios to use during data gathering */
- struct page *pages[PAGES_PER_PACKET];
+ struct page *pages[PACKET_MAX_SIZE / FRAMES_PER_PAGE];
int cache_valid; /* If non-zero, the data for the zone defined */
/* by the sector variable is completely cached */
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
index 4f34d3d60f2..21e5a912485 100644
--- a/include/linux/quotaops.h
+++ b/include/linux/quotaops.h
@@ -190,7 +190,6 @@ static __inline__ int DQUOT_OFF(struct super_block *sb)
*/
#define sb_dquot_ops (NULL)
#define sb_quotactl_ops (NULL)
-#define sync_dquots_dev(dev,type) (NULL)
#define DQUOT_INIT(inode) do { } while(0)
#define DQUOT_DROP(inode) do { } while(0)
#define DQUOT_ALLOC_INODE(inode) (0)
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 981f9aa4335..b87aefa082e 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -240,11 +240,14 @@ extern int rcu_pending(int cpu);
* This means that all preempt_disable code sequences, including NMI and
* hardware-interrupt handlers, in progress on entry will have completed
* before this primitive returns. However, this does not guarantee that
- * softirq handlers will have completed, since in some kernels
+ * softirq handlers will have completed, since in some kernels, these
+ * handlers can run in process context, and can block.
*
* This primitive provides the guarantees made by the (deprecated)
* synchronize_kernel() API. In contrast, synchronize_rcu() only
* guarantees that rcu_read_lock() sections will have completed.
+ * In "classic RCU", these two guarantees happen to be one and
+ * the same, but can differ in realtime RCU implementations.
*/
#define synchronize_sched() synchronize_rcu()
diff --git a/include/linux/reiserfs_acl.h b/include/linux/reiserfs_acl.h
index 0a3605099c4..806ec5b0670 100644
--- a/include/linux/reiserfs_acl.h
+++ b/include/linux/reiserfs_acl.h
@@ -58,9 +58,13 @@ extern struct reiserfs_xattr_handler posix_acl_default_handler;
extern struct reiserfs_xattr_handler posix_acl_access_handler;
#else
-#define reiserfs_get_acl NULL
#define reiserfs_cache_default_acl(inode) 0
+static inline struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
+{
+ return NULL;
+}
+
static inline int reiserfs_xattr_posix_acl_init(void)
{
return 0;
diff --git a/include/linux/security.h b/include/linux/security.h
index bb1da86747c..7cbef482e13 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1499,15 +1499,11 @@ static inline void security_sb_post_pivotroot (struct nameidata *old_nd,
static inline int security_inode_alloc (struct inode *inode)
{
- if (unlikely (IS_PRIVATE (inode)))
- return 0;
return security_ops->inode_alloc_security (inode);
}
static inline void security_inode_free (struct inode *inode)
{
- if (unlikely (IS_PRIVATE (inode)))
- return;
security_ops->inode_free_security (inode);
}
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h
index b68c11a2d6d..be4772ed43c 100644
--- a/include/linux/sunrpc/auth.h
+++ b/include/linux/sunrpc/auth.h
@@ -48,7 +48,7 @@ struct rpc_cred {
/* per-flavor data */
};
-#define RPCAUTH_CRED_LOCKED 0x0001
+#define RPCAUTH_CRED_NEW 0x0001
#define RPCAUTH_CRED_UPTODATE 0x0002
#define RPCAUTH_CRED_MAGIC 0x0f4aa4f0
@@ -83,9 +83,10 @@ struct rpc_auth {
struct rpc_cred_cache * au_credcache;
/* per-flavor data */
};
-#define RPC_AUTH_PROC_CREDS 0x0010 /* process creds (including
- * uid/gid, fs[ug]id, gids)
- */
+
+/* Flags for rpcauth_lookupcred() */
+#define RPCAUTH_LOOKUP_NEW 0x01 /* Accept an uninitialised cred */
+#define RPCAUTH_LOOKUP_ROOTCREDS 0x02 /* This really ought to go! */
/*
* Client authentication ops
@@ -105,6 +106,7 @@ struct rpc_authops {
struct rpc_credops {
const char * cr_name; /* Name of the auth flavour */
+ int (*cr_init)(struct rpc_auth *, struct rpc_cred *);
void (*crdestroy)(struct rpc_cred *);
int (*crmatch)(struct auth_cred *, struct rpc_cred *, int);
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index 5dc94e777fa..43bcd13eb1e 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -42,10 +42,6 @@ extern void mark_free_pages(struct zone *zone);
#ifdef CONFIG_PM
/* kernel/power/swsusp.c */
extern int software_suspend(void);
-
-extern int pm_prepare_console(void);
-extern void pm_restore_console(void);
-
#else
static inline int software_suspend(void)
{
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 3787102e4b1..a7bd3b4558d 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -57,6 +57,7 @@ struct tty_buffer {
unsigned char *flag_buf_ptr;
int used;
int size;
+ int active;
/* Data points here */
unsigned long data[0];
};
@@ -64,6 +65,7 @@ struct tty_buffer {
struct tty_bufhead {
struct work_struct work;
struct semaphore pty_sem;
+ spinlock_t lock;
struct tty_buffer *head; /* Queue head */
struct tty_buffer *tail; /* Active buffer */
struct tty_buffer *free; /* Free queue head */
diff --git a/include/linux/tty_flip.h b/include/linux/tty_flip.h
index be1400e8248..82961eb1988 100644
--- a/include/linux/tty_flip.h
+++ b/include/linux/tty_flip.h
@@ -17,7 +17,7 @@ _INLINE_ int tty_insert_flip_char(struct tty_struct *tty,
unsigned char ch, char flag)
{
struct tty_buffer *tb = tty->buf.tail;
- if (tb && tb->used < tb->size) {
+ if (tb && tb->active && tb->used < tb->size) {
tb->flag_buf_ptr[tb->used] = flag;
tb->char_buf_ptr[tb->used++] = ch;
return 1;
@@ -27,6 +27,11 @@ _INLINE_ int tty_insert_flip_char(struct tty_struct *tty,
_INLINE_ void tty_schedule_flip(struct tty_struct *tty)
{
+ unsigned long flags;
+ spin_lock_irqsave(&tty->buf.lock, flags);
+ if (tty->buf.tail != NULL)
+ tty->buf.tail->active = 0;
+ spin_unlock_irqrestore(&tty->buf.lock, flags);
schedule_delayed_work(&tty->buf.work, 1);
}
diff --git a/include/linux/ufs_fs.h b/include/linux/ufs_fs.h
index 7a6babeca25..b0ffe4356e5 100644
--- a/include/linux/ufs_fs.h
+++ b/include/linux/ufs_fs.h
@@ -148,11 +148,11 @@ typedef __u16 __bitwise __fs16;
#define UFS_USEEFT ((__u16)65535)
#define UFS_FSOK 0x7c269d38
-#define UFS_FSACTIVE ((char)0x00)
-#define UFS_FSCLEAN ((char)0x01)
-#define UFS_FSSTABLE ((char)0x02)
-#define UFS_FSOSF1 ((char)0x03) /* is this correct for DEC OSF/1? */
-#define UFS_FSBAD ((char)0xff)
+#define UFS_FSACTIVE ((__s8)0x00)
+#define UFS_FSCLEAN ((__s8)0x01)
+#define UFS_FSSTABLE ((__s8)0x02)
+#define UFS_FSOSF1 ((__s8)0x03) /* is this correct for DEC OSF/1? */
+#define UFS_FSBAD ((__s8)0xff)
/* From here to next blank line, s_flags for ufs_sb_info */
/* directory entry encoding */
@@ -502,8 +502,7 @@ struct ufs_super_block {
/*
* Convert cylinder group to base address of its global summary info.
*/
-#define fs_cs(indx) \
- s_csp[(indx) >> uspi->s_csshift][(indx) & ~uspi->s_csmask]
+#define fs_cs(indx) s_csp[(indx)]
/*
* Cylinder group block for a file system.
@@ -913,6 +912,7 @@ extern int ufs_sync_inode (struct inode *);
extern void ufs_delete_inode (struct inode *);
extern struct buffer_head * ufs_getfrag (struct inode *, unsigned, int, int *);
extern struct buffer_head * ufs_bread (struct inode *, unsigned, int, int *);
+extern int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create);
/* namei.c */
extern struct file_operations ufs_dir_operations;
diff --git a/include/linux/ufs_fs_sb.h b/include/linux/ufs_fs_sb.h
index c1be4c22648..8ff13c160f3 100644
--- a/include/linux/ufs_fs_sb.h
+++ b/include/linux/ufs_fs_sb.h
@@ -25,7 +25,7 @@ struct ufs_csum;
struct ufs_sb_info {
struct ufs_sb_private_info * s_uspi;
- struct ufs_csum * s_csp[UFS_MAXCSBUFS];
+ struct ufs_csum * s_csp;
unsigned s_bytesex;
unsigned s_flags;
struct buffer_head ** s_ucg;
diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h
index 67856eb93b4..dac43b15a5b 100644
--- a/include/net/netfilter/nf_conntrack_l3proto.h
+++ b/include/net/netfilter/nf_conntrack_l3proto.h
@@ -88,12 +88,6 @@ extern struct nf_conntrack_l3proto *nf_ct_l3protos[AF_MAX];
extern int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto);
extern void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto);
-static inline struct nf_conntrack_l3proto *
-__nf_ct_l3proto_find(u_int16_t l3proto)
-{
- return nf_ct_l3protos[l3proto];
-}
-
extern struct nf_conntrack_l3proto *
nf_ct_l3proto_find_get(u_int16_t l3proto);
@@ -103,4 +97,13 @@ extern void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p);
extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4;
extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6;
extern struct nf_conntrack_l3proto nf_conntrack_generic_l3proto;
+
+static inline struct nf_conntrack_l3proto *
+__nf_ct_l3proto_find(u_int16_t l3proto)
+{
+ if (unlikely(l3proto >= AF_MAX))
+ return &nf_conntrack_generic_l3proto;
+ return nf_ct_l3protos[l3proto];
+}
+
#endif /*_NF_CONNTRACK_L3PROTO_H*/
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index 8c522ae031b..072f407848a 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -700,7 +700,7 @@ struct sctp_chunk {
__u8 ecn_ce_done; /* Have we processed the ECN CE bit? */
__u8 pdiscard; /* Discard the whole packet now? */
__u8 tsn_gap_acked; /* Is this chunk acked by a GAP ACK? */
- __u8 fast_retransmit; /* Is this chunk fast retransmitted? */
+ __s8 fast_retransmit; /* Is this chunk fast retransmitted? */
__u8 tsn_missing_report; /* Data chunk missing counter. */
};
diff --git a/include/net/sock.h b/include/net/sock.h
index 1806e5b6141..30758035d61 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1354,12 +1354,12 @@ extern int sock_get_timestamp(struct sock *, struct timeval __user *);
* Enable debug/info messages
*/
-#if 0
-#define NETDEBUG(fmt, args...) do { } while (0)
-#define LIMIT_NETDEBUG(fmt, args...) do { } while(0)
-#else
+#ifdef CONFIG_NETDEBUG
#define NETDEBUG(fmt, args...) printk(fmt,##args)
#define LIMIT_NETDEBUG(fmt, args...) do { if (net_ratelimit()) printk(fmt,##args); } while(0)
+#else
+#define NETDEBUG(fmt, args...) do { } while (0)
+#define LIMIT_NETDEBUG(fmt, args...) do { } while(0)
#endif
/*
diff --git a/init/Kconfig b/init/Kconfig
index b9923b1434a..8b7abae87bf 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -31,19 +31,8 @@ config EXPERIMENTAL
you say Y here, you will be offered the choice of using features or
drivers that are currently considered to be in the alpha-test phase.
-config CLEAN_COMPILE
- bool "Select only drivers expected to compile cleanly" if EXPERIMENTAL
- default y
- help
- Select this option if you don't even want to see the option
- to configure known-broken drivers.
-
- If unsure, say Y
-
config BROKEN
bool
- depends on !CLEAN_COMPILE
- default y
config BROKEN_ON_SMP
bool
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index fe2f71f92ae..ba42b0a7696 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -641,7 +641,7 @@ static void guarantee_online_mems(const struct cpuset *cs, nodemask_t *pmask)
* task has been modifying its cpuset.
*/
-void cpuset_update_task_memory_state()
+void cpuset_update_task_memory_state(void)
{
int my_cpusets_mem_gen;
struct task_struct *tsk = current;
diff --git a/kernel/intermodule.c b/kernel/intermodule.c
index 0cbe633420f..55b1e5b85db 100644
--- a/kernel/intermodule.c
+++ b/kernel/intermodule.c
@@ -179,3 +179,6 @@ EXPORT_SYMBOL(inter_module_register);
EXPORT_SYMBOL(inter_module_unregister);
EXPORT_SYMBOL(inter_module_get_request);
EXPORT_SYMBOL(inter_module_put);
+
+MODULE_LICENSE("GPL");
+
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 3ea6325228d..fef1af8a73c 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -344,23 +344,6 @@ void __kprobes kprobe_flush_task(struct task_struct *tk)
spin_unlock_irqrestore(&kretprobe_lock, flags);
}
-/*
- * This kprobe pre_handler is registered with every kretprobe. When probe
- * hits it will set up the return probe.
- */
-static int __kprobes pre_handler_kretprobe(struct kprobe *p,
- struct pt_regs *regs)
-{
- struct kretprobe *rp = container_of(p, struct kretprobe, kp);
- unsigned long flags = 0;
-
- /*TODO: consider to only swap the RA after the last pre_handler fired */
- spin_lock_irqsave(&kretprobe_lock, flags);
- arch_prepare_kretprobe(rp, regs);
- spin_unlock_irqrestore(&kretprobe_lock, flags);
- return 0;
-}
-
static inline void free_rp_inst(struct kretprobe *rp)
{
struct kretprobe_instance *ri;
@@ -578,6 +561,23 @@ void __kprobes unregister_jprobe(struct jprobe *jp)
#ifdef ARCH_SUPPORTS_KRETPROBES
+/*
+ * This kprobe pre_handler is registered with every kretprobe. When probe
+ * hits it will set up the return probe.
+ */
+static int __kprobes pre_handler_kretprobe(struct kprobe *p,
+ struct pt_regs *regs)
+{
+ struct kretprobe *rp = container_of(p, struct kretprobe, kp);
+ unsigned long flags = 0;
+
+ /*TODO: consider to only swap the RA after the last pre_handler fired */
+ spin_lock_irqsave(&kretprobe_lock, flags);
+ arch_prepare_kretprobe(rp, regs);
+ spin_unlock_irqrestore(&kretprobe_lock, flags);
+ return 0;
+}
+
int __kprobes register_kretprobe(struct kretprobe *rp)
{
int ret = 0;
@@ -631,12 +631,12 @@ void __kprobes unregister_kretprobe(struct kretprobe *rp)
unregister_kprobe(&rp->kp);
/* No race here */
spin_lock_irqsave(&kretprobe_lock, flags);
- free_rp_inst(rp);
while ((ri = get_used_rp_inst(rp)) != NULL) {
ri->rp = NULL;
hlist_del(&ri->uflist);
}
spin_unlock_irqrestore(&kretprobe_lock, flags);
+ free_rp_inst(rp);
}
static int __init init_kprobes(void)
diff --git a/kernel/module.c b/kernel/module.c
index 618ed6e23ec..e058aedf6b9 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2092,7 +2092,8 @@ static unsigned long mod_find_symname(struct module *mod, const char *name)
unsigned int i;
for (i = 0; i < mod->num_symtab; i++)
- if (strcmp(name, mod->strtab+mod->symtab[i].st_name) == 0)
+ if (strcmp(name, mod->strtab+mod->symtab[i].st_name) == 0 &&
+ mod->symtab[i].st_info != 'U')
return mod->symtab[i].st_value;
return 0;
}
diff --git a/kernel/sched.c b/kernel/sched.c
index f77f23f8f47..bc38804e40d 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -5551,13 +5551,15 @@ static void calibrate_migration_costs(const cpumask_t *cpu_map)
-1
#endif
);
- printk("migration_cost=");
- for (distance = 0; distance <= max_distance; distance++) {
- if (distance)
- printk(",");
- printk("%ld", (long)migration_cost[distance] / 1000);
+ if (system_state == SYSTEM_BOOTING) {
+ printk("migration_cost=");
+ for (distance = 0; distance <= max_distance; distance++) {
+ if (distance)
+ printk(",");
+ printk("%ld", (long)migration_cost[distance] / 1000);
+ }
+ printk("\n");
}
- printk("\n");
j1 = jiffies;
if (migration_debug)
printk("migration: %ld seconds\n", (j1-j0)/HZ);
@@ -6109,7 +6111,7 @@ void __init sched_init(void)
runqueue_t *rq;
int i, j, k;
- for (i = 0; i < NR_CPUS; i++) {
+ for_each_cpu(i) {
prio_array_t *array;
rq = cpu_rq(i);
diff --git a/kernel/signal.c b/kernel/signal.c
index d3efafd8109..b373fc2420d 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -283,7 +283,7 @@ static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags,
return(q);
}
-static inline void __sigqueue_free(struct sigqueue *q)
+static void __sigqueue_free(struct sigqueue *q)
{
if (q->flags & SIGQUEUE_PREALLOC)
return;
diff --git a/kernel/time.c b/kernel/time.c
index 1f23e683d6a..804539165d8 100644
--- a/kernel/time.c
+++ b/kernel/time.c
@@ -637,15 +637,16 @@ void set_normalized_timespec(struct timespec *ts, time_t sec, long nsec)
*
* Returns the timespec representation of the nsec parameter.
*/
-inline struct timespec ns_to_timespec(const nsec_t nsec)
+struct timespec ns_to_timespec(const nsec_t nsec)
{
struct timespec ts;
- if (nsec)
- ts.tv_sec = div_long_long_rem_signed(nsec, NSEC_PER_SEC,
- &ts.tv_nsec);
- else
- ts.tv_sec = ts.tv_nsec = 0;
+ if (!nsec)
+ return (struct timespec) {0, 0};
+
+ ts.tv_sec = div_long_long_rem_signed(nsec, NSEC_PER_SEC, &ts.tv_nsec);
+ if (unlikely(nsec < 0))
+ set_normalized_timespec(&ts, ts.tv_sec, ts.tv_nsec);
return ts;
}
diff --git a/lib/int_sqrt.c b/lib/int_sqrt.c
index a5d2cdc5684..fd355a99327 100644
--- a/lib/int_sqrt.c
+++ b/lib/int_sqrt.c
@@ -15,7 +15,7 @@ unsigned long int_sqrt(unsigned long x)
op = x;
res = 0;
- one = 1 << 30;
+ one = 1UL << (BITS_PER_LONG - 2);
while (one > op)
one >>= 2;
diff --git a/lib/ts_bm.c b/lib/ts_bm.c
index 8a8b3a16133..c4c1ac5fbd1 100644
--- a/lib/ts_bm.c
+++ b/lib/ts_bm.c
@@ -94,10 +94,28 @@ next: bs = bm->bad_shift[text[shift-i]];
return UINT_MAX;
}
+static int subpattern(u8 *pattern, int i, int j, int g)
+{
+ int x = i+g-1, y = j+g-1, ret = 0;
+
+ while(pattern[x--] == pattern[y--]) {
+ if (y < 0) {
+ ret = 1;
+ break;
+ }
+ if (--g == 0) {
+ ret = pattern[i-1] != pattern[j-1];
+ break;
+ }
+ }
+
+ return ret;
+}
+
static void compute_prefix_tbl(struct ts_bm *bm, const u8 *pattern,
unsigned int len)
{
- int i, j, ended, l[ASIZE];
+ int i, j, g;
for (i = 0; i < ASIZE; i++)
bm->bad_shift[i] = len;
@@ -106,23 +124,15 @@ static void compute_prefix_tbl(struct ts_bm *bm, const u8 *pattern,
/* Compute the good shift array, used to match reocurrences
* of a subpattern */
- for (i = 1; i < bm->patlen; i++) {
- for (j = 0; j < bm->patlen && bm->pattern[bm->patlen - 1 - j]
- == bm->pattern[bm->patlen - 1 - i - j]; j++);
- l[i] = j;
- }
-
bm->good_shift[0] = 1;
for (i = 1; i < bm->patlen; i++)
bm->good_shift[i] = bm->patlen;
- for (i = bm->patlen - 1; i > 0; i--)
- bm->good_shift[l[i]] = i;
- ended = 0;
- for (i = 0; i < bm->patlen; i++) {
- if (l[i] == bm->patlen - 1 - i)
- ended = i;
- if (ended)
- bm->good_shift[i] = ended;
+ for (i = bm->patlen-1, g = 1; i > 0; g++, i--) {
+ for (j = i-1; j >= 1-g ; j--)
+ if (subpattern(bm->pattern, i, j, g)) {
+ bm->good_shift[g] = bm->patlen-j-g;
+ break;
+ }
}
}
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index b21d78c941b..ceb3ebb3c39 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -444,6 +444,15 @@ retry:
page = alloc_huge_page(vma, address);
if (!page) {
hugetlb_put_quota(mapping);
+ /*
+ * No huge pages available. So this is an OOM
+ * condition but we do not want to trigger the OOM
+ * killer, so we return VM_FAULT_SIGBUS.
+ *
+ * A program using hugepages may fault with Bus Error
+ * because no huge pages are available in the cpuset, per
+ * memory policy or because all are in use!
+ */
goto out;
}
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index 27da6d5c77b..3bd7fb7e4b7 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -1159,6 +1159,7 @@ static inline unsigned interleave_nid(struct mempolicy *pol,
return interleave_nodes(pol);
}
+#ifdef CONFIG_HUGETLBFS
/* Return a zonelist suitable for a huge page allocation. */
struct zonelist *huge_zonelist(struct vm_area_struct *vma, unsigned long addr)
{
@@ -1172,6 +1173,7 @@ struct zonelist *huge_zonelist(struct vm_area_struct *vma, unsigned long addr)
}
return zonelist_policy(GFP_HIGHUSER, pol);
}
+#endif
/* Allocate a page in interleaved policy.
Own path because it needs to do special accounting. */
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 44b4eb4202d..dde04ff4be3 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1213,18 +1213,21 @@ static void __get_page_state(struct page_state *ret, int nr, cpumask_t *cpumask)
{
int cpu = 0;
- memset(ret, 0, sizeof(*ret));
+ memset(ret, 0, nr * sizeof(unsigned long));
cpus_and(*cpumask, *cpumask, cpu_online_map);
cpu = first_cpu(*cpumask);
while (cpu < NR_CPUS) {
unsigned long *in, *out, off;
+ if (!cpu_isset(cpu, *cpumask))
+ continue;
+
in = (unsigned long *)&per_cpu(page_states, cpu);
cpu = next_cpu(cpu, *cpumask);
- if (cpu < NR_CPUS)
+ if (likely(cpu < NR_CPUS))
prefetch(&per_cpu(page_states, cpu));
out = (unsigned long *)ret;
@@ -1886,8 +1889,7 @@ static void setup_pagelist_highmark(struct per_cpu_pageset *p,
* not check if the processor is online before following the pageset pointer.
* Other parts of the kernel may not check if the zone is available.
*/
-static struct per_cpu_pageset
- boot_pageset[NR_CPUS];
+static struct per_cpu_pageset boot_pageset[NR_CPUS];
/*
* Dynamically allocate memory for the
diff --git a/mm/slab.c b/mm/slab.c
index 71370256a7e..d66c2b0d971 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -294,6 +294,7 @@ struct kmem_list3 {
unsigned long next_reap;
int free_touched;
unsigned int free_limit;
+ unsigned int colour_next; /* Per-node cache coloring */
spinlock_t list_lock;
struct array_cache *shared; /* shared per node */
struct array_cache **alien; /* on other nodes */
@@ -344,6 +345,7 @@ static void kmem_list3_init(struct kmem_list3 *parent)
INIT_LIST_HEAD(&parent->slabs_free);
parent->shared = NULL;
parent->alien = NULL;
+ parent->colour_next = 0;
spin_lock_init(&parent->list_lock);
parent->free_objects = 0;
parent->free_touched = 0;
@@ -390,7 +392,6 @@ struct kmem_cache {
size_t colour; /* cache colouring range */
unsigned int colour_off; /* colour offset */
- unsigned int colour_next; /* cache colouring */
struct kmem_cache *slabp_cache;
unsigned int slab_size;
unsigned int dflags; /* dynamic flags */
@@ -883,14 +884,14 @@ static void __drain_alien_cache(struct kmem_cache *cachep,
}
}
-static void drain_alien_cache(struct kmem_cache *cachep, struct kmem_list3 *l3)
+static void drain_alien_cache(struct kmem_cache *cachep, struct array_cache **alien)
{
int i = 0;
struct array_cache *ac;
unsigned long flags;
for_each_online_node(i) {
- ac = l3->alien[i];
+ ac = alien[i];
if (ac) {
spin_lock_irqsave(&ac->lock, flags);
__drain_alien_cache(cachep, ac, i);
@@ -899,9 +900,18 @@ static void drain_alien_cache(struct kmem_cache *cachep, struct kmem_list3 *l3)
}
}
#else
-#define alloc_alien_cache(node, limit) do { } while (0)
-#define free_alien_cache(ac_ptr) do { } while (0)
-#define drain_alien_cache(cachep, l3) do { } while (0)
+
+#define drain_alien_cache(cachep, alien) do { } while (0)
+
+static inline struct array_cache **alloc_alien_cache(int node, int limit)
+{
+ return (struct array_cache **) 0x01020304ul;
+}
+
+static inline void free_alien_cache(struct array_cache **ac_ptr)
+{
+}
+
#endif
static int __devinit cpuup_callback(struct notifier_block *nfb,
@@ -935,6 +945,11 @@ static int __devinit cpuup_callback(struct notifier_block *nfb,
l3->next_reap = jiffies + REAPTIMEOUT_LIST3 +
((unsigned long)cachep) % REAPTIMEOUT_LIST3;
+ /*
+ * The l3s don't come and go as CPUs come and
+ * go. cache_chain_mutex is sufficient
+ * protection here.
+ */
cachep->nodelists[node] = l3;
}
@@ -949,26 +964,46 @@ static int __devinit cpuup_callback(struct notifier_block *nfb,
& array cache's */
list_for_each_entry(cachep, &cache_chain, next) {
struct array_cache *nc;
+ struct array_cache *shared;
+ struct array_cache **alien;
nc = alloc_arraycache(node, cachep->limit,
- cachep->batchcount);
+ cachep->batchcount);
if (!nc)
goto bad;
+ shared = alloc_arraycache(node,
+ cachep->shared * cachep->batchcount,
+ 0xbaadf00d);
+ if (!shared)
+ goto bad;
+
+ alien = alloc_alien_cache(node, cachep->limit);
+ if (!alien)
+ goto bad;
cachep->array[cpu] = nc;
l3 = cachep->nodelists[node];
BUG_ON(!l3);
- if (!l3->shared) {
- if (!(nc = alloc_arraycache(node,
- cachep->shared *
- cachep->batchcount,
- 0xbaadf00d)))
- goto bad;
- /* we are serialised from CPU_DEAD or
- CPU_UP_CANCELLED by the cpucontrol lock */
- l3->shared = nc;
+ spin_lock_irq(&l3->list_lock);
+ if (!l3->shared) {
+ /*
+ * We are serialised from CPU_DEAD or
+ * CPU_UP_CANCELLED by the cpucontrol lock
+ */
+ l3->shared = shared;
+ shared = NULL;
+ }
+#ifdef CONFIG_NUMA
+ if (!l3->alien) {
+ l3->alien = alien;
+ alien = NULL;
}
+#endif
+ spin_unlock_irq(&l3->list_lock);
+
+ kfree(shared);
+ free_alien_cache(alien);
}
mutex_unlock(&cache_chain_mutex);
break;
@@ -977,25 +1012,34 @@ static int __devinit cpuup_callback(struct notifier_block *nfb,
break;
#ifdef CONFIG_HOTPLUG_CPU
case CPU_DEAD:
+ /*
+ * Even if all the cpus of a node are down, we don't free the
+ * kmem_list3 of any cache. This to avoid a race between
+ * cpu_down, and a kmalloc allocation from another cpu for
+ * memory from the node of the cpu going down. The list3
+ * structure is usually allocated from kmem_cache_create() and
+ * gets destroyed at kmem_cache_destroy().
+ */
/* fall thru */
case CPU_UP_CANCELED:
mutex_lock(&cache_chain_mutex);
list_for_each_entry(cachep, &cache_chain, next) {
struct array_cache *nc;
+ struct array_cache *shared;
+ struct array_cache **alien;
cpumask_t mask;
mask = node_to_cpumask(node);
- spin_lock_irq(&cachep->spinlock);
/* cpu is dead; no one can alloc from it. */
nc = cachep->array[cpu];
cachep->array[cpu] = NULL;
l3 = cachep->nodelists[node];
if (!l3)
- goto unlock_cache;
+ goto free_array_cache;
- spin_lock(&l3->list_lock);
+ spin_lock_irq(&l3->list_lock);
/* Free limit for this kmem_list3 */
l3->free_limit -= cachep->batchcount;
@@ -1003,34 +1047,44 @@ static int __devinit cpuup_callback(struct notifier_block *nfb,
free_block(cachep, nc->entry, nc->avail, node);
if (!cpus_empty(mask)) {
- spin_unlock(&l3->list_lock);
- goto unlock_cache;
+ spin_unlock_irq(&l3->list_lock);
+ goto free_array_cache;
}
- if (l3->shared) {
+ shared = l3->shared;
+ if (shared) {
free_block(cachep, l3->shared->entry,
l3->shared->avail, node);
- kfree(l3->shared);
l3->shared = NULL;
}
- if (l3->alien) {
- drain_alien_cache(cachep, l3);
- free_alien_cache(l3->alien);
- l3->alien = NULL;
- }
- /* free slabs belonging to this node */
- if (__node_shrink(cachep, node)) {
- cachep->nodelists[node] = NULL;
- spin_unlock(&l3->list_lock);
- kfree(l3);
- } else {
- spin_unlock(&l3->list_lock);
+ alien = l3->alien;
+ l3->alien = NULL;
+
+ spin_unlock_irq(&l3->list_lock);
+
+ kfree(shared);
+ if (alien) {
+ drain_alien_cache(cachep, alien);
+ free_alien_cache(alien);
}
- unlock_cache:
- spin_unlock_irq(&cachep->spinlock);
+free_array_cache:
kfree(nc);
}
+ /*
+ * In the previous loop, all the objects were freed to
+ * the respective cache's slabs, now we can go ahead and
+ * shrink each nodelist to its limit.
+ */
+ list_for_each_entry(cachep, &cache_chain, next) {
+ l3 = cachep->nodelists[node];
+ if (!l3)
+ continue;
+ spin_lock_irq(&l3->list_lock);
+ /* free slabs belonging to this node */
+ __node_shrink(cachep, node);
+ spin_unlock_irq(&l3->list_lock);
+ }
mutex_unlock(&cache_chain_mutex);
break;
#endif
@@ -1119,7 +1173,6 @@ void __init kmem_cache_init(void)
BUG();
cache_cache.colour = left_over / cache_cache.colour_off;
- cache_cache.colour_next = 0;
cache_cache.slab_size = ALIGN(cache_cache.num * sizeof(kmem_bufctl_t) +
sizeof(struct slab), cache_line_size());
@@ -2011,18 +2064,16 @@ static void drain_cpu_caches(struct kmem_cache *cachep)
smp_call_function_all_cpus(do_drain, cachep);
check_irq_on();
- spin_lock_irq(&cachep->spinlock);
for_each_online_node(node) {
l3 = cachep->nodelists[node];
if (l3) {
- spin_lock(&l3->list_lock);
+ spin_lock_irq(&l3->list_lock);
drain_array_locked(cachep, l3->shared, 1, node);
- spin_unlock(&l3->list_lock);
+ spin_unlock_irq(&l3->list_lock);
if (l3->alien)
- drain_alien_cache(cachep, l3);
+ drain_alien_cache(cachep, l3->alien);
}
}
- spin_unlock_irq(&cachep->spinlock);
}
static int __node_shrink(struct kmem_cache *cachep, int node)
@@ -2324,20 +2375,20 @@ static int cache_grow(struct kmem_cache *cachep, gfp_t flags, int nodeid)
*/
ctor_flags |= SLAB_CTOR_ATOMIC;
- /* About to mess with non-constant members - lock. */
+ /* Take the l3 list lock to change the colour_next on this node */
check_irq_off();
- spin_lock(&cachep->spinlock);
+ l3 = cachep->nodelists[nodeid];
+ spin_lock(&l3->list_lock);
/* Get colour for the slab, and cal the next value. */
- offset = cachep->colour_next;
- cachep->colour_next++;
- if (cachep->colour_next >= cachep->colour)
- cachep->colour_next = 0;
- offset *= cachep->colour_off;
+ offset = l3->colour_next;
+ l3->colour_next++;
+ if (l3->colour_next >= cachep->colour)
+ l3->colour_next = 0;
+ spin_unlock(&l3->list_lock);
- spin_unlock(&cachep->spinlock);
+ offset *= cachep->colour_off;
- check_irq_off();
if (local_flags & __GFP_WAIT)
local_irq_enable();
@@ -2367,7 +2418,6 @@ static int cache_grow(struct kmem_cache *cachep, gfp_t flags, int nodeid)
if (local_flags & __GFP_WAIT)
local_irq_disable();
check_irq_off();
- l3 = cachep->nodelists[nodeid];
spin_lock(&l3->list_lock);
/* Make slab active. */
@@ -2725,6 +2775,7 @@ static void *__cache_alloc_node(struct kmem_cache *cachep, gfp_t flags, int node
BUG_ON(!l3);
retry:
+ check_irq_off();
spin_lock(&l3->list_lock);
entry = l3->slabs_partial.next;
if (entry == &l3->slabs_partial) {
@@ -3304,11 +3355,11 @@ static int do_tune_cpucache(struct kmem_cache *cachep, int limit, int batchcount
smp_call_function_all_cpus(do_ccupdate_local, (void *)&new);
check_irq_on();
- spin_lock_irq(&cachep->spinlock);
+ spin_lock(&cachep->spinlock);
cachep->batchcount = batchcount;
cachep->limit = limit;
cachep->shared = shared;
- spin_unlock_irq(&cachep->spinlock);
+ spin_unlock(&cachep->spinlock);
for_each_online_cpu(i) {
struct array_cache *ccold = new.new[i];
@@ -3440,7 +3491,7 @@ static void cache_reap(void *unused)
l3 = searchp->nodelists[numa_node_id()];
if (l3->alien)
- drain_alien_cache(searchp, l3);
+ drain_alien_cache(searchp, l3->alien);
spin_lock_irq(&l3->list_lock);
drain_array_locked(searchp, cpu_cache_get(searchp), 0,
@@ -3564,8 +3615,7 @@ static int s_show(struct seq_file *m, void *p)
int node;
struct kmem_list3 *l3;
- check_irq_on();
- spin_lock_irq(&cachep->spinlock);
+ spin_lock(&cachep->spinlock);
active_objs = 0;
num_slabs = 0;
for_each_online_node(node) {
@@ -3573,7 +3623,8 @@ static int s_show(struct seq_file *m, void *p)
if (!l3)
continue;
- spin_lock(&l3->list_lock);
+ check_irq_on();
+ spin_lock_irq(&l3->list_lock);
list_for_each(q, &l3->slabs_full) {
slabp = list_entry(q, struct slab, list);
@@ -3598,9 +3649,10 @@ static int s_show(struct seq_file *m, void *p)
num_slabs++;
}
free_objects += l3->free_objects;
- shared_avail += l3->shared->avail;
+ if (l3->shared)
+ shared_avail += l3->shared->avail;
- spin_unlock(&l3->list_lock);
+ spin_unlock_irq(&l3->list_lock);
}
num_slabs += active_slabs;
num_objs = num_slabs * cachep->num;
@@ -3644,7 +3696,7 @@ static int s_show(struct seq_file *m, void *p)
}
#endif
seq_putc(m, '\n');
- spin_unlock_irq(&cachep->spinlock);
+ spin_unlock(&cachep->spinlock);
return 0;
}
diff --git a/net/802/psnap.c b/net/802/psnap.c
index 4d638944d93..34e42968b47 100644
--- a/net/802/psnap.c
+++ b/net/802/psnap.c
@@ -59,8 +59,10 @@ static int snap_rcv(struct sk_buff *skb, struct net_device *dev,
proto = find_snap_client(skb->h.raw);
if (proto) {
/* Pass the frame on. */
+ u8 *hdr = skb->data;
skb->h.raw += 5;
skb_pull(skb, 5);
+ skb_postpull_rcsum(skb, hdr, 5);
rc = proto->rcvfunc(skb, dev, &snap_packet_type, orig_dev);
} else {
skb->sk = NULL;
diff --git a/net/Kconfig b/net/Kconfig
index bc603d9aea5..5126f58d9c4 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -27,6 +27,13 @@ if NET
menu "Networking options"
+config NETDEBUG
+ bool "Network packet debugging"
+ help
+ You can say Y here if you want to get additional messages useful in
+ debugging bad packets, but can overwhelm logs under denial of service
+ attacks.
+
source "net/packet/Kconfig"
source "net/unix/Kconfig"
source "net/xfrm/Kconfig"
diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c
index ce617b3dbbb..802baf755ef 100644
--- a/net/bridge/netfilter/ebt_ulog.c
+++ b/net/bridge/netfilter/ebt_ulog.c
@@ -46,7 +46,7 @@
#define PRINTR(format, args...) do { if (net_ratelimit()) \
printk(format , ## args); } while (0)
-static unsigned int nlbufsiz = 4096;
+static unsigned int nlbufsiz = NLMSG_GOODSIZE;
module_param(nlbufsiz, uint, 0600);
MODULE_PARM_DESC(nlbufsiz, "netlink buffer size (number of bytes) "
"(defaults to 4096)");
@@ -98,12 +98,14 @@ static void ulog_timer(unsigned long data)
static struct sk_buff *ulog_alloc_skb(unsigned int size)
{
struct sk_buff *skb;
+ unsigned int n;
- skb = alloc_skb(nlbufsiz, GFP_ATOMIC);
+ n = max(size, nlbufsiz);
+ skb = alloc_skb(n, GFP_ATOMIC);
if (!skb) {
PRINTR(KERN_ERR "ebt_ulog: can't alloc whole buffer "
- "of size %ub!\n", nlbufsiz);
- if (size < nlbufsiz) {
+ "of size %ub!\n", n);
+ if (n > size) {
/* try to allocate only as much as we need for
* current packet */
skb = alloc_skb(size, GFP_ATOMIC);
diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
index 00729b3604f..cbd4020cc84 100644
--- a/net/bridge/netfilter/ebtables.c
+++ b/net/bridge/netfilter/ebtables.c
@@ -934,6 +934,13 @@ static int do_replace(void __user *user, unsigned int len)
BUGPRINT("Entries_size never zero\n");
return -EINVAL;
}
+ /* overflow check */
+ if (tmp.nentries >= ((INT_MAX - sizeof(struct ebt_table_info)) / NR_CPUS -
+ SMP_CACHE_BYTES) / sizeof(struct ebt_counter))
+ return -ENOMEM;
+ if (tmp.num_counters >= INT_MAX / sizeof(struct ebt_counter))
+ return -ENOMEM;
+
countersize = COUNTER_OFFSET(tmp.nentries) *
(highest_possible_processor_id()+1);
newinfo = (struct ebt_table_info *)
diff --git a/net/core/dev.c b/net/core/dev.c
index ffb82073056..2afb0de9532 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3237,7 +3237,7 @@ static int __init net_dev_init(void)
* Initialise the packet receive queues.
*/
- for (i = 0; i < NR_CPUS; i++) {
+ for_each_cpu(i) {
struct softnet_data *queue;
queue = &per_cpu(softnet_data, i);
diff --git a/net/core/utils.c b/net/core/utils.c
index ac1d1fcf867..fdc4f38bc46 100644
--- a/net/core/utils.c
+++ b/net/core/utils.c
@@ -121,7 +121,7 @@ void __init net_random_init(void)
{
int i;
- for (i = 0; i < NR_CPUS; i++) {
+ for_each_cpu(i) {
struct nrnd_state *state = &per_cpu(net_rand_state,i);
__net_srandom(state, i+jiffies);
}
@@ -133,7 +133,7 @@ static int net_random_reseed(void)
unsigned long seed[NR_CPUS];
get_random_bytes(seed, sizeof(seed));
- for (i = 0; i < NR_CPUS; i++) {
+ for_each_cpu(i) {
struct nrnd_state *state = &per_cpu(net_rand_state,i);
__net_srandom(state, seed[i]);
}
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 105039eb762..4d1c40972a4 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -385,7 +385,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
u32 daddr;
if (ip_options_echo(&icmp_param->replyopts, skb))
- goto out;
+ return;
if (icmp_xmit_lock())
return;
@@ -416,7 +416,6 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
ip_rt_put(rt);
out_unlock:
icmp_xmit_unlock();
-out:;
}
@@ -525,7 +524,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info)
iph->tos;
if (ip_options_echo(&icmp_param.replyopts, skb_in))
- goto ende;
+ goto out_unlock;
/*
diff --git a/net/ipv4/multipath_wrandom.c b/net/ipv4/multipath_wrandom.c
index d34a9fa608e..342d0b9098f 100644
--- a/net/ipv4/multipath_wrandom.c
+++ b/net/ipv4/multipath_wrandom.c
@@ -228,7 +228,7 @@ static void wrandom_set_nhinfo(__u32 network,
struct multipath_dest *d, *target_dest = NULL;
/* store the weight information for a certain route */
- spin_lock(&state[state_idx].lock);
+ spin_lock_bh(&state[state_idx].lock);
/* find state entry for gateway or add one if necessary */
list_for_each_entry_rcu(r, &state[state_idx].head, list) {
@@ -276,7 +276,7 @@ static void wrandom_set_nhinfo(__u32 network,
* we are finished
*/
- spin_unlock(&state[state_idx].lock);
+ spin_unlock_bh(&state[state_idx].lock);
}
static void __multipath_free(struct rcu_head *head)
@@ -302,7 +302,7 @@ static void wrandom_flush(void)
for (i = 0; i < MULTIPATH_STATE_SIZE; ++i) {
struct multipath_route *r;
- spin_lock(&state[i].lock);
+ spin_lock_bh(&state[i].lock);
list_for_each_entry_rcu(r, &state[i].head, list) {
struct multipath_dest *d;
list_for_each_entry_rcu(d, &r->dests, list) {
@@ -315,7 +315,7 @@ static void wrandom_flush(void)
__multipath_free);
}
- spin_unlock(&state[i].lock);
+ spin_unlock_bh(&state[i].lock);
}
}
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index afe3d8f8177..dd1048be8a0 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -807,6 +807,13 @@ static int do_replace(void __user *user, unsigned int len)
if (len != sizeof(tmp) + tmp.size)
return -ENOPROTOOPT;
+ /* overflow check */
+ if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
+ SMP_CACHE_BYTES)
+ return -ENOMEM;
+ if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
+ return -ENOMEM;
+
newinfo = xt_alloc_table_info(tmp.size);
if (!newinfo)
return -ENOMEM;
diff --git a/net/ipv4/netfilter/ip_conntrack_netlink.c b/net/ipv4/netfilter/ip_conntrack_netlink.c
index c9ebbe0d2d9..e0b5926c76f 100644
--- a/net/ipv4/netfilter/ip_conntrack_netlink.c
+++ b/net/ipv4/netfilter/ip_conntrack_netlink.c
@@ -1216,7 +1216,7 @@ static int ctnetlink_expect_event(struct notifier_block *this,
b = skb->tail;
- type |= NFNL_SUBSYS_CTNETLINK << 8;
+ type |= NFNL_SUBSYS_CTNETLINK_EXP << 8;
nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg));
nfmsg = NLMSG_DATA(nlh);
@@ -1567,6 +1567,7 @@ static struct nfnetlink_subsystem ctnl_exp_subsys = {
};
MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK);
+MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_EXP);
static int __init ctnetlink_init(void)
{
diff --git a/net/ipv4/netfilter/ip_conntrack_tftp.c b/net/ipv4/netfilter/ip_conntrack_tftp.c
index d3c5a371f99..4ba4463cec2 100644
--- a/net/ipv4/netfilter/ip_conntrack_tftp.c
+++ b/net/ipv4/netfilter/ip_conntrack_tftp.c
@@ -71,6 +71,7 @@ static int tftp_help(struct sk_buff **pskb,
exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple;
exp->mask.src.ip = 0xffffffff;
+ exp->mask.src.u.udp.port = 0;
exp->mask.dst.ip = 0xffffffff;
exp->mask.dst.u.udp.port = 0xffff;
exp->mask.dst.protonum = 0xff;
diff --git a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
index ad438fb185b..92c54999a19 100644
--- a/net/ipv4/netfilter/ip_nat_standalone.c
+++ b/net/ipv4/netfilter/ip_nat_standalone.c
@@ -209,8 +209,8 @@ ip_nat_in(unsigned int hooknum,
&& (ct = ip_conntrack_get(*pskb, &ctinfo)) != NULL) {
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
- if (ct->tuplehash[dir].tuple.src.ip !=
- ct->tuplehash[!dir].tuple.dst.ip) {
+ if (ct->tuplehash[dir].tuple.dst.ip !=
+ ct->tuplehash[!dir].tuple.src.ip) {
dst_release((*pskb)->dst);
(*pskb)->dst = NULL;
}
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
index 2371b2062c2..16f47c675fe 100644
--- a/net/ipv4/netfilter/ip_tables.c
+++ b/net/ipv4/netfilter/ip_tables.c
@@ -921,6 +921,13 @@ do_replace(void __user *user, unsigned int len)
if (len != sizeof(tmp) + tmp.size)
return -ENOPROTOOPT;
+ /* overflow check */
+ if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
+ SMP_CACHE_BYTES)
+ return -ENOMEM;
+ if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
+ return -ENOMEM;
+
newinfo = xt_alloc_table_info(tmp.size);
if (!newinfo)
return -ENOMEM;
diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c
index 641dbc47765..180a9ea57b6 100644
--- a/net/ipv4/netfilter/ipt_ULOG.c
+++ b/net/ipv4/netfilter/ipt_ULOG.c
@@ -35,6 +35,10 @@
* each nlgroup you are using, so the total kernel memory usage increases
* by that factor.
*
+ * Actually you should use nlbufsiz a bit smaller than PAGE_SIZE, since
+ * nlbufsiz is used with alloc_skb, which adds another
+ * sizeof(struct skb_shared_info). Use NLMSG_GOODSIZE instead.
+ *
* flushtimeout:
* Specify, after how many hundredths of a second the queue should be
* flushed even if it is not full yet.
@@ -76,7 +80,7 @@ MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NFLOG);
#define PRINTR(format, args...) do { if (net_ratelimit()) printk(format , ## args); } while (0)
-static unsigned int nlbufsiz = 4096;
+static unsigned int nlbufsiz = NLMSG_GOODSIZE;
module_param(nlbufsiz, uint, 0400);
MODULE_PARM_DESC(nlbufsiz, "netlink buffer size");
@@ -143,22 +147,26 @@ static void ulog_timer(unsigned long data)
static struct sk_buff *ulog_alloc_skb(unsigned int size)
{
struct sk_buff *skb;
+ unsigned int n;
/* alloc skb which should be big enough for a whole
* multipart message. WARNING: has to be <= 131000
* due to slab allocator restrictions */
- skb = alloc_skb(nlbufsiz, GFP_ATOMIC);
+ n = max(size, nlbufsiz);
+ skb = alloc_skb(n, GFP_ATOMIC);
if (!skb) {
- PRINTR("ipt_ULOG: can't alloc whole buffer %ub!\n",
- nlbufsiz);
+ PRINTR("ipt_ULOG: can't alloc whole buffer %ub!\n", n);
- /* try to allocate only as much as we need for
- * current packet */
+ if (n > size) {
+ /* try to allocate only as much as we need for
+ * current packet */
- skb = alloc_skb(size, GFP_ATOMIC);
- if (!skb)
- PRINTR("ipt_ULOG: can't even allocate %ub\n", size);
+ skb = alloc_skb(size, GFP_ATOMIC);
+ if (!skb)
+ PRINTR("ipt_ULOG: can't even allocate %ub\n",
+ size);
+ }
}
return skb;
diff --git a/net/ipv4/netfilter/ipt_policy.c b/net/ipv4/netfilter/ipt_policy.c
index 18ca8258a1c..5a7a265280f 100644
--- a/net/ipv4/netfilter/ipt_policy.c
+++ b/net/ipv4/netfilter/ipt_policy.c
@@ -26,10 +26,13 @@ MODULE_LICENSE("GPL");
static inline int
match_xfrm_state(struct xfrm_state *x, const struct ipt_policy_elem *e)
{
-#define MATCH(x,y) (!e->match.x || ((e->x == (y)) ^ e->invert.x))
+#define MATCH_ADDR(x,y,z) (!e->match.x || \
+ ((e->x.a4.s_addr == (e->y.a4.s_addr & (z))) \
+ ^ e->invert.x))
+#define MATCH(x,y) (!e->match.x || ((e->x == (y)) ^ e->invert.x))
- return MATCH(saddr, x->props.saddr.a4 & e->smask) &&
- MATCH(daddr, x->id.daddr.a4 & e->dmask) &&
+ return MATCH_ADDR(saddr, smask, x->props.saddr.a4) &&
+ MATCH_ADDR(daddr, dmask, x->id.daddr.a4) &&
MATCH(proto, x->id.proto) &&
MATCH(mode, x->props.mode) &&
MATCH(spi, x->id.spi) &&
@@ -89,7 +92,7 @@ match_policy_out(const struct sk_buff *skb, const struct ipt_policy_info *info)
return 0;
}
- return strict ? 1 : 0;
+ return strict ? i == info->len : 0;
}
static int match(const struct sk_buff *skb,
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index 39d49dc333a..1b167c4bb3b 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -49,7 +49,7 @@ static int fold_prot_inuse(struct proto *proto)
int res = 0;
int cpu;
- for (cpu = 0; cpu < NR_CPUS; cpu++)
+ for_each_cpu(cpu)
res += proto->stats[cpu].inuse;
return res;
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index d328d598614..1db50487916 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -3321,9 +3321,7 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
switch (event) {
case RTM_NEWADDR:
- dst_hold(&ifp->rt->u.dst);
- if (ip6_ins_rt(ifp->rt, NULL, NULL, NULL))
- dst_release(&ifp->rt->u.dst);
+ ip6_ins_rt(ifp->rt, NULL, NULL, NULL);
if (ifp->idev->cnf.forwarding)
addrconf_join_anycast(ifp);
break;
@@ -3334,8 +3332,6 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
dst_hold(&ifp->rt->u.dst);
if (ip6_del_rt(ifp->rt, NULL, NULL, NULL))
dst_free(&ifp->rt->u.dst);
- else
- dst_release(&ifp->rt->u.dst);
break;
}
}
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 064ffab82a9..6c9711ac1c0 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -369,12 +369,6 @@ int inet6_destroy_sock(struct sock *sk)
struct sk_buff *skb;
struct ipv6_txoptions *opt;
- /*
- * Release destination entry
- */
-
- sk_dst_reset(sk);
-
/* Release rx options */
if ((skb = xchg(&np->pktoptions, NULL)) != NULL)
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 847068fd336..74ff56c322f 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -978,6 +978,13 @@ do_replace(void __user *user, unsigned int len)
if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
return -EFAULT;
+ /* overflow check */
+ if (tmp.size >= (INT_MAX - sizeof(struct xt_table_info)) / NR_CPUS -
+ SMP_CACHE_BYTES)
+ return -ENOMEM;
+ if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
+ return -ENOMEM;
+
newinfo = xt_alloc_table_info(tmp.size);
if (!newinfo)
return -ENOMEM;
diff --git a/net/ipv6/netfilter/ip6t_policy.c b/net/ipv6/netfilter/ip6t_policy.c
index afe1cc4c18a..3d39ec92404 100644
--- a/net/ipv6/netfilter/ip6t_policy.c
+++ b/net/ipv6/netfilter/ip6t_policy.c
@@ -26,8 +26,9 @@ MODULE_LICENSE("GPL");
static inline int
match_xfrm_state(struct xfrm_state *x, const struct ip6t_policy_elem *e)
{
-#define MATCH_ADDR(x,y,z) (!e->match.x || \
- ((ip6_masked_addrcmp((z), &e->x, &e->y)) == 0) ^ e->invert.x)
+#define MATCH_ADDR(x,y,z) (!e->match.x || \
+ ((!ip6_masked_addrcmp(&e->x.a6, &e->y.a6, z)) \
+ ^ e->invert.x))
#define MATCH(x,y) (!e->match.x || ((e->x == (y)) ^ e->invert.x))
return MATCH_ADDR(saddr, smask, (struct in6_addr *)&x->props.saddr.a6) &&
@@ -91,7 +92,7 @@ match_policy_out(const struct sk_buff *skb, const struct ip6t_policy_info *info)
return 0;
}
- return strict ? 1 : 0;
+ return strict ? i == info->len : 0;
}
static int match(const struct sk_buff *skb,
diff --git a/net/ipv6/proc.c b/net/ipv6/proc.c
index 50a13e75d70..4238b1ed886 100644
--- a/net/ipv6/proc.c
+++ b/net/ipv6/proc.c
@@ -38,7 +38,7 @@ static int fold_prot_inuse(struct proto *proto)
int res = 0;
int cpu;
- for (cpu=0; cpu<NR_CPUS; cpu++)
+ for_each_cpu(cpu)
res += proto->stats[cpu].inuse;
return res;
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index 62bb509f05d..0ce337a1d97 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -188,7 +188,7 @@ extern struct nf_conntrack_protocol nf_conntrack_generic_protocol;
struct nf_conntrack_protocol *
__nf_ct_proto_find(u_int16_t l3proto, u_int8_t protocol)
{
- if (unlikely(nf_ct_protos[l3proto] == NULL))
+ if (unlikely(l3proto >= AF_MAX || nf_ct_protos[l3proto] == NULL))
return &nf_conntrack_generic_protocol;
return nf_ct_protos[l3proto][protocol];
diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c
index ab0c920f0d3..6f210f39976 100644
--- a/net/netfilter/nf_conntrack_ftp.c
+++ b/net/netfilter/nf_conntrack_ftp.c
@@ -657,8 +657,6 @@ static int __init init(void)
/* FIXME should be configurable whether IPv4 and IPv6 FTP connections
are tracked or not - YK */
for (i = 0; i < ports_c; i++) {
- memset(&ftp[i], 0, sizeof(struct nf_conntrack_helper));
-
ftp[i][0].tuple.src.l3num = PF_INET;
ftp[i][1].tuple.src.l3num = PF_INET6;
for (j = 0; j < 2; j++) {
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 73ab16bc7d4..9ff3463037e 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -1232,7 +1232,7 @@ static int ctnetlink_expect_event(struct notifier_block *this,
b = skb->tail;
- type |= NFNL_SUBSYS_CTNETLINK << 8;
+ type |= NFNL_SUBSYS_CTNETLINK_EXP << 8;
nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg));
nfmsg = NLMSG_DATA(nlh);
@@ -1589,6 +1589,7 @@ static struct nfnetlink_subsystem ctnl_exp_subsys = {
};
MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK);
+MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK_EXP);
static int __init ctnetlink_init(void)
{
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
index e10512e229b..3b3c781b40c 100644
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -37,7 +37,7 @@
#include "../bridge/br_private.h"
#endif
-#define NFULNL_NLBUFSIZ_DEFAULT 4096
+#define NFULNL_NLBUFSIZ_DEFAULT NLMSG_GOODSIZE
#define NFULNL_TIMEOUT_DEFAULT 100 /* every second */
#define NFULNL_QTHRESH_DEFAULT 100 /* 100 packets */
@@ -314,24 +314,28 @@ static struct sk_buff *nfulnl_alloc_skb(unsigned int inst_size,
unsigned int pkt_size)
{
struct sk_buff *skb;
+ unsigned int n;
UDEBUG("entered (%u, %u)\n", inst_size, pkt_size);
/* alloc skb which should be big enough for a whole multipart
* message. WARNING: has to be <= 128k due to slab restrictions */
- skb = alloc_skb(inst_size, GFP_ATOMIC);
+ n = max(inst_size, pkt_size);
+ skb = alloc_skb(n, GFP_ATOMIC);
if (!skb) {
PRINTR("nfnetlink_log: can't alloc whole buffer (%u bytes)\n",
inst_size);
- /* try to allocate only as much as we need for current
- * packet */
+ if (n > pkt_size) {
+ /* try to allocate only as much as we need for current
+ * packet */
- skb = alloc_skb(pkt_size, GFP_ATOMIC);
- if (!skb)
- PRINTR("nfnetlink_log: can't even alloc %u bytes\n",
- pkt_size);
+ skb = alloc_skb(pkt_size, GFP_ATOMIC);
+ if (!skb)
+ PRINTR("nfnetlink_log: can't even alloc %u "
+ "bytes\n", pkt_size);
+ }
}
return skb;
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
index 18ed9c5d209..cac38b2e147 100644
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -825,7 +825,8 @@ nfqnl_recv_verdict(struct sock *ctnl, struct sk_buff *skb,
}
if (nfqa[NFQA_MARK-1])
- skb->nfmark = ntohl(*(u_int32_t *)NFA_DATA(nfqa[NFQA_MARK-1]));
+ entry->skb->nfmark = ntohl(*(u_int32_t *)
+ NFA_DATA(nfqa[NFQA_MARK-1]));
issue_verdict(entry, verdict);
instance_put(queue);
diff --git a/net/sctp/output.c b/net/sctp/output.c
index a40991ef72c..437cba7260a 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -608,7 +608,7 @@ static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet,
* When a Fast Retransmit is being performed the sender SHOULD
* ignore the value of cwnd and SHOULD NOT delay retransmission.
*/
- if (!chunk->fast_retransmit)
+ if (chunk->fast_retransmit <= 0)
if (transport->flight_size >= transport->cwnd) {
retval = SCTP_XMIT_RWND_FULL;
goto finish;
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index efb72faba20..f148f9576dd 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -406,7 +406,7 @@ void sctp_retransmit_mark(struct sctp_outq *q,
* chunks that are not yet acked should be added to the
* retransmit queue.
*/
- if ((fast_retransmit && chunk->fast_retransmit) ||
+ if ((fast_retransmit && (chunk->fast_retransmit > 0)) ||
(!fast_retransmit && !chunk->tsn_gap_acked)) {
/* RFC 2960 6.2.1 Processing a Received SACK
*
@@ -603,7 +603,8 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
/* Mark the chunk as ineligible for fast retransmit
* after it is retransmitted.
*/
- chunk->fast_retransmit = 0;
+ if (chunk->fast_retransmit > 0)
+ chunk->fast_retransmit = -1;
*start_timer = 1;
q->empty = 0;
@@ -621,7 +622,8 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt,
list_for_each(lchunk1, lqueue) {
chunk1 = list_entry(lchunk1, struct sctp_chunk,
transmitted_list);
- chunk1->fast_retransmit = 0;
+ if (chunk1->fast_retransmit > 0)
+ chunk1->fast_retransmit = -1;
}
}
}
@@ -1562,11 +1564,11 @@ static void sctp_mark_missing(struct sctp_outq *q,
/*
* M4) If any DATA chunk is found to have a
* 'TSN.Missing.Report'
- * value larger than or equal to 4, mark that chunk for
+ * value larger than or equal to 3, mark that chunk for
* retransmission and start the fast retransmit procedure.
*/
- if (chunk->tsn_missing_report >= 4) {
+ if (chunk->tsn_missing_report >= 3) {
chunk->fast_retransmit = 1;
do_fast_retransmit = 1;
}
diff --git a/net/socket.c b/net/socket.c
index b38a263853c..a00851f981d 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -2078,7 +2078,7 @@ void socket_seq_show(struct seq_file *seq)
int cpu;
int counter = 0;
- for (cpu = 0; cpu < NR_CPUS; cpu++)
+ for_each_cpu(cpu)
counter += per_cpu(sockets_in_use, cpu);
/* It can be negative, by the way. 8) */
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index 9ac1b8c26c0..8d6f1a176b1 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -184,7 +184,7 @@ rpcauth_gc_credcache(struct rpc_auth *auth, struct hlist_head *free)
*/
struct rpc_cred *
rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred,
- int taskflags)
+ int flags)
{
struct rpc_cred_cache *cache = auth->au_credcache;
HLIST_HEAD(free);
@@ -193,7 +193,7 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred,
*cred = NULL;
int nr = 0;
- if (!(taskflags & RPC_TASK_ROOTCREDS))
+ if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS))
nr = acred->uid & RPC_CREDCACHE_MASK;
retry:
spin_lock(&rpc_credcache_lock);
@@ -202,7 +202,7 @@ retry:
hlist_for_each_safe(pos, next, &cache->hashtable[nr]) {
struct rpc_cred *entry;
entry = hlist_entry(pos, struct rpc_cred, cr_hash);
- if (entry->cr_ops->crmatch(acred, entry, taskflags)) {
+ if (entry->cr_ops->crmatch(acred, entry, flags)) {
hlist_del(&entry->cr_hash);
cred = entry;
break;
@@ -224,7 +224,7 @@ retry:
rpcauth_destroy_credlist(&free);
if (!cred) {
- new = auth->au_ops->crcreate(auth, acred, taskflags);
+ new = auth->au_ops->crcreate(auth, acred, flags);
if (!IS_ERR(new)) {
#ifdef RPC_DEBUG
new->cr_magic = RPCAUTH_CRED_MAGIC;
@@ -232,13 +232,21 @@ retry:
goto retry;
} else
cred = new;
+ } else if ((cred->cr_flags & RPCAUTH_CRED_NEW)
+ && cred->cr_ops->cr_init != NULL
+ && !(flags & RPCAUTH_LOOKUP_NEW)) {
+ int res = cred->cr_ops->cr_init(auth, cred);
+ if (res < 0) {
+ put_rpccred(cred);
+ cred = ERR_PTR(res);
+ }
}
return (struct rpc_cred *) cred;
}
struct rpc_cred *
-rpcauth_lookupcred(struct rpc_auth *auth, int taskflags)
+rpcauth_lookupcred(struct rpc_auth *auth, int flags)
{
struct auth_cred acred = {
.uid = current->fsuid,
@@ -250,7 +258,7 @@ rpcauth_lookupcred(struct rpc_auth *auth, int taskflags)
dprintk("RPC: looking up %s cred\n",
auth->au_ops->au_name);
get_group_info(acred.group_info);
- ret = auth->au_ops->lookup_cred(auth, &acred, taskflags);
+ ret = auth->au_ops->lookup_cred(auth, &acred, flags);
put_group_info(acred.group_info);
return ret;
}
@@ -265,11 +273,14 @@ rpcauth_bindcred(struct rpc_task *task)
.group_info = current->group_info,
};
struct rpc_cred *ret;
+ int flags = 0;
dprintk("RPC: %4d looking up %s cred\n",
task->tk_pid, task->tk_auth->au_ops->au_name);
get_group_info(acred.group_info);
- ret = auth->au_ops->lookup_cred(auth, &acred, task->tk_flags);
+ if (task->tk_flags & RPC_TASK_ROOTCREDS)
+ flags |= RPCAUTH_LOOKUP_ROOTCREDS;
+ ret = auth->au_ops->lookup_cred(auth, &acred, flags);
if (!IS_ERR(ret))
task->tk_msg.rpc_cred = ret;
else
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 8d782282ec1..bb46efd92e5 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -158,6 +158,7 @@ gss_cred_set_ctx(struct rpc_cred *cred, struct gss_cl_ctx *ctx)
old = gss_cred->gc_ctx;
gss_cred->gc_ctx = ctx;
cred->cr_flags |= RPCAUTH_CRED_UPTODATE;
+ cred->cr_flags &= ~RPCAUTH_CRED_NEW;
write_unlock(&gss_ctx_lock);
if (old)
gss_put_ctx(old);
@@ -580,7 +581,7 @@ gss_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
} else {
struct auth_cred acred = { .uid = uid };
spin_unlock(&gss_auth->lock);
- cred = rpcauth_lookup_credcache(clnt->cl_auth, &acred, 0);
+ cred = rpcauth_lookup_credcache(clnt->cl_auth, &acred, RPCAUTH_LOOKUP_NEW);
if (IS_ERR(cred)) {
err = PTR_ERR(cred);
goto err_put_ctx;
@@ -758,13 +759,13 @@ gss_destroy_cred(struct rpc_cred *rc)
* Lookup RPCSEC_GSS cred for the current process
*/
static struct rpc_cred *
-gss_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags)
+gss_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
{
- return rpcauth_lookup_credcache(auth, acred, taskflags);
+ return rpcauth_lookup_credcache(auth, acred, flags);
}
static struct rpc_cred *
-gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags)
+gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
{
struct gss_auth *gss_auth = container_of(auth, struct gss_auth, rpc_auth);
struct gss_cred *cred = NULL;
@@ -785,13 +786,8 @@ gss_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int taskflags)
*/
cred->gc_flags = 0;
cred->gc_base.cr_ops = &gss_credops;
+ cred->gc_base.cr_flags = RPCAUTH_CRED_NEW;
cred->gc_service = gss_auth->service;
- do {
- err = gss_create_upcall(gss_auth, cred);
- } while (err == -EAGAIN);
- if (err < 0)
- goto out_err;
-
return &cred->gc_base;
out_err:
@@ -801,13 +797,34 @@ out_err:
}
static int
-gss_match(struct auth_cred *acred, struct rpc_cred *rc, int taskflags)
+gss_cred_init(struct rpc_auth *auth, struct rpc_cred *cred)
+{
+ struct gss_auth *gss_auth = container_of(auth, struct gss_auth, rpc_auth);
+ struct gss_cred *gss_cred = container_of(cred,struct gss_cred, gc_base);
+ int err;
+
+ do {
+ err = gss_create_upcall(gss_auth, gss_cred);
+ } while (err == -EAGAIN);
+ return err;
+}
+
+static int
+gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags)
{
struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base);
+ /*
+ * If the searchflags have set RPCAUTH_LOOKUP_NEW, then
+ * we don't really care if the credential has expired or not,
+ * since the caller should be prepared to reinitialise it.
+ */
+ if ((flags & RPCAUTH_LOOKUP_NEW) && (rc->cr_flags & RPCAUTH_CRED_NEW))
+ goto out;
/* Don't match with creds that have expired. */
if (gss_cred->gc_ctx && time_after(jiffies, gss_cred->gc_ctx->gc_expiry))
return 0;
+out:
return (rc->cr_uid == acred->uid);
}
@@ -1241,6 +1258,7 @@ static struct rpc_authops authgss_ops = {
static struct rpc_credops gss_credops = {
.cr_name = "AUTH_GSS",
.crdestroy = gss_destroy_cred,
+ .cr_init = gss_cred_init,
.crmatch = gss_match,
.crmarshal = gss_marshal,
.crrefresh = gss_refresh,
diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c
index 1b3ed4fd198..df14b6bfbf1 100644
--- a/net/sunrpc/auth_unix.c
+++ b/net/sunrpc/auth_unix.c
@@ -75,7 +75,7 @@ unx_create_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags)
atomic_set(&cred->uc_count, 1);
cred->uc_flags = RPCAUTH_CRED_UPTODATE;
- if (flags & RPC_TASK_ROOTCREDS) {
+ if (flags & RPCAUTH_LOOKUP_ROOTCREDS) {
cred->uc_uid = 0;
cred->uc_gid = 0;
cred->uc_gids[0] = NOGROUP;
@@ -108,12 +108,12 @@ unx_destroy_cred(struct rpc_cred *cred)
* request root creds (e.g. for NFS swapping).
*/
static int
-unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int taskflags)
+unx_match(struct auth_cred *acred, struct rpc_cred *rcred, int flags)
{
struct unx_cred *cred = (struct unx_cred *) rcred;
int i;
- if (!(taskflags & RPC_TASK_ROOTCREDS)) {
+ if (!(flags & RPCAUTH_LOOKUP_ROOTCREDS)) {
int groups;
if (cred->uc_uid != acred->uid
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
index 9764c80ab0b..a5c0c7b6e15 100644
--- a/net/sunrpc/rpc_pipe.c
+++ b/net/sunrpc/rpc_pipe.c
@@ -38,44 +38,42 @@ static kmem_cache_t *rpc_inode_cachep __read_mostly;
#define RPC_UPCALL_TIMEOUT (30*HZ)
-static void
-__rpc_purge_list(struct rpc_inode *rpci, struct list_head *head, int err)
+static void rpc_purge_list(struct rpc_inode *rpci, struct list_head *head,
+ void (*destroy_msg)(struct rpc_pipe_msg *), int err)
{
struct rpc_pipe_msg *msg;
- void (*destroy_msg)(struct rpc_pipe_msg *);
- destroy_msg = rpci->ops->destroy_msg;
- while (!list_empty(head)) {
+ if (list_empty(head))
+ return;
+ do {
msg = list_entry(head->next, struct rpc_pipe_msg, list);
- list_del_init(&msg->list);
+ list_del(&msg->list);
msg->errno = err;
destroy_msg(msg);
- }
-}
-
-static void
-__rpc_purge_upcall(struct inode *inode, int err)
-{
- struct rpc_inode *rpci = RPC_I(inode);
-
- __rpc_purge_list(rpci, &rpci->pipe, err);
- rpci->pipelen = 0;
+ } while (!list_empty(head));
wake_up(&rpci->waitq);
}
static void
rpc_timeout_upcall_queue(void *data)
{
+ LIST_HEAD(free_list);
struct rpc_inode *rpci = (struct rpc_inode *)data;
struct inode *inode = &rpci->vfs_inode;
+ void (*destroy_msg)(struct rpc_pipe_msg *);
- mutex_lock(&inode->i_mutex);
- if (rpci->ops == NULL)
- goto out;
- if (rpci->nreaders == 0 && !list_empty(&rpci->pipe))
- __rpc_purge_upcall(inode, -ETIMEDOUT);
-out:
- mutex_unlock(&inode->i_mutex);
+ spin_lock(&inode->i_lock);
+ if (rpci->ops == NULL) {
+ spin_unlock(&inode->i_lock);
+ return;
+ }
+ destroy_msg = rpci->ops->destroy_msg;
+ if (rpci->nreaders == 0) {
+ list_splice_init(&rpci->pipe, &free_list);
+ rpci->pipelen = 0;
+ }
+ spin_unlock(&inode->i_lock);
+ rpc_purge_list(rpci, &free_list, destroy_msg, -ETIMEDOUT);
}
int
@@ -84,7 +82,7 @@ rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg)
struct rpc_inode *rpci = RPC_I(inode);
int res = -EPIPE;
- mutex_lock(&inode->i_mutex);
+ spin_lock(&inode->i_lock);
if (rpci->ops == NULL)
goto out;
if (rpci->nreaders) {
@@ -100,7 +98,7 @@ rpc_queue_upcall(struct inode *inode, struct rpc_pipe_msg *msg)
res = 0;
}
out:
- mutex_unlock(&inode->i_mutex);
+ spin_unlock(&inode->i_lock);
wake_up(&rpci->waitq);
return res;
}
@@ -115,21 +113,29 @@ static void
rpc_close_pipes(struct inode *inode)
{
struct rpc_inode *rpci = RPC_I(inode);
+ struct rpc_pipe_ops *ops;
mutex_lock(&inode->i_mutex);
- if (rpci->ops != NULL) {
+ ops = rpci->ops;
+ if (ops != NULL) {
+ LIST_HEAD(free_list);
+
+ spin_lock(&inode->i_lock);
rpci->nreaders = 0;
- __rpc_purge_list(rpci, &rpci->in_upcall, -EPIPE);
- __rpc_purge_upcall(inode, -EPIPE);
- rpci->nwriters = 0;
- if (rpci->ops->release_pipe)
- rpci->ops->release_pipe(inode);
+ list_splice_init(&rpci->in_upcall, &free_list);
+ list_splice_init(&rpci->pipe, &free_list);
+ rpci->pipelen = 0;
rpci->ops = NULL;
+ spin_unlock(&inode->i_lock);
+ rpc_purge_list(rpci, &free_list, ops->destroy_msg, -EPIPE);
+ rpci->nwriters = 0;
+ if (ops->release_pipe)
+ ops->release_pipe(inode);
+ cancel_delayed_work(&rpci->queue_timeout);
+ flush_scheduled_work();
}
rpc_inode_setowner(inode, NULL);
mutex_unlock(&inode->i_mutex);
- cancel_delayed_work(&rpci->queue_timeout);
- flush_scheduled_work();
}
static struct inode *
@@ -177,16 +183,26 @@ rpc_pipe_release(struct inode *inode, struct file *filp)
goto out;
msg = (struct rpc_pipe_msg *)filp->private_data;
if (msg != NULL) {
+ spin_lock(&inode->i_lock);
msg->errno = -EAGAIN;
- list_del_init(&msg->list);
+ list_del(&msg->list);
+ spin_unlock(&inode->i_lock);
rpci->ops->destroy_msg(msg);
}
if (filp->f_mode & FMODE_WRITE)
rpci->nwriters --;
- if (filp->f_mode & FMODE_READ)
+ if (filp->f_mode & FMODE_READ) {
rpci->nreaders --;
- if (!rpci->nreaders)
- __rpc_purge_upcall(inode, -EAGAIN);
+ if (rpci->nreaders == 0) {
+ LIST_HEAD(free_list);
+ spin_lock(&inode->i_lock);
+ list_splice_init(&rpci->pipe, &free_list);
+ rpci->pipelen = 0;
+ spin_unlock(&inode->i_lock);
+ rpc_purge_list(rpci, &free_list,
+ rpci->ops->destroy_msg, -EAGAIN);
+ }
+ }
if (rpci->ops->release_pipe)
rpci->ops->release_pipe(inode);
out:
@@ -209,6 +225,7 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
}
msg = filp->private_data;
if (msg == NULL) {
+ spin_lock(&inode->i_lock);
if (!list_empty(&rpci->pipe)) {
msg = list_entry(rpci->pipe.next,
struct rpc_pipe_msg,
@@ -218,6 +235,7 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
filp->private_data = msg;
msg->copied = 0;
}
+ spin_unlock(&inode->i_lock);
if (msg == NULL)
goto out_unlock;
}
@@ -225,7 +243,9 @@ rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
res = rpci->ops->upcall(filp, msg, buf, len);
if (res < 0 || msg->len == msg->copied) {
filp->private_data = NULL;
- list_del_init(&msg->list);
+ spin_lock(&inode->i_lock);
+ list_del(&msg->list);
+ spin_unlock(&inode->i_lock);
rpci->ops->destroy_msg(msg);
}
out_unlock:
@@ -610,7 +630,7 @@ rpc_lookup_negative(char *path, struct nameidata *nd)
return ERR_PTR(error);
dir = nd->dentry->d_inode;
mutex_lock(&dir->i_mutex);
- dentry = lookup_hash(nd);
+ dentry = lookup_one_len(nd->last.name, nd->dentry, nd->last.len);
if (IS_ERR(dentry))
goto out_err;
if (dentry->d_inode) {
@@ -672,7 +692,7 @@ rpc_rmdir(char *path)
return error;
dir = nd.dentry->d_inode;
mutex_lock(&dir->i_mutex);
- dentry = lookup_hash(&nd);
+ dentry = lookup_one_len(nd.last.name, nd.dentry, nd.last.len);
if (IS_ERR(dentry)) {
error = PTR_ERR(dentry);
goto out_release;
@@ -733,7 +753,7 @@ rpc_unlink(char *path)
return error;
dir = nd.dentry->d_inode;
mutex_lock(&dir->i_mutex);
- dentry = lookup_hash(&nd);
+ dentry = lookup_one_len(nd.last.name, nd.dentry, nd.last.len);
if (IS_ERR(dentry)) {
error = PTR_ERR(dentry);
goto out_release;
diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile
index 5760e057ecb..d64aae85c37 100644
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -123,7 +123,17 @@ KBUILD_HAVE_NLS := $(shell \
then echo yes ; \
else echo no ; fi)
ifeq ($(KBUILD_HAVE_NLS),no)
-HOSTCFLAGS += -DKBUILD_NO_NLS
+ HOSTCFLAGS += -DKBUILD_NO_NLS
+else
+ KBUILD_NEED_LINTL := $(shell \
+ if echo -e "\#include <libintl.h>\nint main(int a, char** b) { gettext(\"\"); return 0; }\n" | \
+ $(HOSTCC) $(HOSTCFLAGS) -x c - -o /dev/null> /dev/null 2>&1 ; \
+ then echo no ; \
+ else echo yes ; fi)
+ ifeq ($(KBUILD_NEED_LINTL),yes)
+ HOSTLOADLIBES_conf += -lintl
+ HOSTLOADLIBES_mconf += -lintl
+ endif
endif
# generated files seem to need this to find local include files
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index 90db5c76cf6..0c62798ac7d 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -67,9 +67,10 @@ asmlinkage long sys_add_key(const char __user *_type,
description = kmalloc(dlen + 1, GFP_KERNEL);
if (!description)
goto error;
+ description[dlen] = '\0';
ret = -EFAULT;
- if (copy_from_user(description, _description, dlen + 1) != 0)
+ if (copy_from_user(description, _description, dlen) != 0)
goto error2;
/* pull the payload in if one was supplied */
@@ -161,9 +162,10 @@ asmlinkage long sys_request_key(const char __user *_type,
description = kmalloc(dlen + 1, GFP_KERNEL);
if (!description)
goto error;
+ description[dlen] = '\0';
ret = -EFAULT;
- if (copy_from_user(description, _description, dlen + 1) != 0)
+ if (copy_from_user(description, _description, dlen) != 0)
goto error2;
/* pull the callout info into kernel space */
@@ -182,9 +184,10 @@ asmlinkage long sys_request_key(const char __user *_type,
callout_info = kmalloc(dlen + 1, GFP_KERNEL);
if (!callout_info)
goto error2;
+ callout_info[dlen] = '\0';
ret = -EFAULT;
- if (copy_from_user(callout_info, _callout_info, dlen + 1) != 0)
+ if (copy_from_user(callout_info, _callout_info, dlen) != 0)
goto error3;
}
@@ -279,9 +282,10 @@ long keyctl_join_session_keyring(const char __user *_name)
name = kmalloc(nlen + 1, GFP_KERNEL);
if (!name)
goto error;
+ name[nlen] = '\0';
ret = -EFAULT;
- if (copy_from_user(name, _name, nlen + 1) != 0)
+ if (copy_from_user(name, _name, nlen) != 0)
goto error2;
}
@@ -583,9 +587,10 @@ long keyctl_keyring_search(key_serial_t ringid,
description = kmalloc(dlen + 1, GFP_KERNEL);
if (!description)
goto error;
+ description[dlen] = '\0';
ret = -EFAULT;
- if (copy_from_user(description, _description, dlen + 1) != 0)
+ if (copy_from_user(description, _description, dlen) != 0)
goto error2;
/* get the keyring at which to begin the search */
diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig
index b59582b9228..502f78f13f5 100644
--- a/security/selinux/Kconfig
+++ b/security/selinux/Kconfig
@@ -1,6 +1,6 @@
config SECURITY_SELINUX
bool "NSA SELinux Support"
- depends on SECURITY && NET && INET
+ depends on SECURITY_NETWORK && NET && INET
default n
help
This selects NSA Security-Enhanced Linux (SELinux).
diff --git a/security/selinux/Makefile b/security/selinux/Makefile
index 06d54d9d20a..688c0a267b6 100644
--- a/security/selinux/Makefile
+++ b/security/selinux/Makefile
@@ -4,9 +4,7 @@
obj-$(CONFIG_SECURITY_SELINUX) := selinux.o ss/
-selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o
-
-selinux-$(CONFIG_SECURITY_NETWORK) += netif.o
+selinux-y := avc.o hooks.o selinuxfs.o netlink.o nlmsgtab.o netif.o
selinux-$(CONFIG_SECURITY_NETWORK_XFRM) += xfrm.o
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 4ae834d89bc..b7773bf68ef 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -232,7 +232,6 @@ static void superblock_free_security(struct super_block *sb)
kfree(sbsec);
}
-#ifdef CONFIG_SECURITY_NETWORK
static int sk_alloc_security(struct sock *sk, int family, gfp_t priority)
{
struct sk_security_struct *ssec;
@@ -261,7 +260,6 @@ static void sk_free_security(struct sock *sk)
sk->sk_security = NULL;
kfree(ssec);
}
-#endif /* CONFIG_SECURITY_NETWORK */
/* The security server must be initialized before
any labeling or access decisions can be provided. */
@@ -2736,8 +2734,6 @@ static void selinux_task_to_inode(struct task_struct *p,
return;
}
-#ifdef CONFIG_SECURITY_NETWORK
-
/* Returns error only if unable to parse addresses */
static int selinux_parse_skb_ipv4(struct sk_buff *skb, struct avc_audit_data *ad)
{
@@ -3556,15 +3552,6 @@ static unsigned int selinux_ipv6_postroute_last(unsigned int hooknum,
#endif /* CONFIG_NETFILTER */
-#else
-
-static inline int selinux_nlmsg_perm(struct sock *sk, struct sk_buff *skb)
-{
- return 0;
-}
-
-#endif /* CONFIG_SECURITY_NETWORK */
-
static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
{
struct task_security_struct *tsec;
@@ -4340,7 +4327,6 @@ static struct security_operations selinux_ops = {
.getprocattr = selinux_getprocattr,
.setprocattr = selinux_setprocattr,
-#ifdef CONFIG_SECURITY_NETWORK
.unix_stream_connect = selinux_socket_unix_stream_connect,
.unix_may_send = selinux_socket_unix_may_send,
@@ -4362,7 +4348,6 @@ static struct security_operations selinux_ops = {
.sk_alloc_security = selinux_sk_alloc_security,
.sk_free_security = selinux_sk_free_security,
.sk_getsid = selinux_sk_getsid_security,
-#endif
#ifdef CONFIG_SECURITY_NETWORK_XFRM
.xfrm_policy_alloc_security = selinux_xfrm_policy_alloc,
@@ -4440,7 +4425,7 @@ next_sb:
all processes and objects when they are created. */
security_initcall(selinux_init);
-#if defined(CONFIG_SECURITY_NETWORK) && defined(CONFIG_NETFILTER)
+#if defined(CONFIG_NETFILTER)
static struct nf_hook_ops selinux_ipv4_op = {
.hook = selinux_ipv4_postroute_last,
@@ -4501,13 +4486,13 @@ static void selinux_nf_ip_exit(void)
}
#endif
-#else /* CONFIG_SECURITY_NETWORK && CONFIG_NETFILTER */
+#else /* CONFIG_NETFILTER */
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
#define selinux_nf_ip_exit()
#endif
-#endif /* CONFIG_SECURITY_NETWORK && CONFIG_NETFILTER */
+#endif /* CONFIG_NETFILTER */
#ifdef CONFIG_SECURITY_SELINUX_DISABLE
int selinux_disable(void)
diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c
index 54147c1f636..149feb41065 100644
--- a/sound/arm/aaci.c
+++ b/sound/arm/aaci.c
@@ -882,14 +882,20 @@ static int __devinit aaci_probe(struct amba_device *dev, void *id)
writel(0x1fff, aaci->base + AACI_INTCLR);
writel(aaci->maincr, aaci->base + AACI_MAINCR);
+ ret = aaci_probe_ac97(aaci);
+ if (ret)
+ goto out;
+
/*
- * Size the FIFOs.
+ * Size the FIFOs (must be multiple of 16).
*/
aaci->fifosize = aaci_size_fifo(aaci);
-
- ret = aaci_probe_ac97(aaci);
- if (ret)
+ if (aaci->fifosize & 15) {
+ printk(KERN_WARNING "AACI: fifosize = %d not supported\n",
+ aaci->fifosize);
+ ret = -ENODEV;
goto out;
+ }
ret = aaci_init_pcm(aaci);
if (ret)